diff options
Diffstat (limited to 'fs/9p')
-rw-r--r-- | fs/9p/9p.h | 375 | ||||
-rw-r--r-- | fs/9p/Makefile | 6 | ||||
-rw-r--r-- | fs/9p/conv.c | 845 | ||||
-rw-r--r-- | fs/9p/conv.h | 50 | ||||
-rw-r--r-- | fs/9p/debug.h | 77 | ||||
-rw-r--r-- | fs/9p/error.c | 93 | ||||
-rw-r--r-- | fs/9p/error.h | 177 | ||||
-rw-r--r-- | fs/9p/fcall.c | 427 | ||||
-rw-r--r-- | fs/9p/fcprint.c | 345 | ||||
-rw-r--r-- | fs/9p/fid.c | 168 | ||||
-rw-r--r-- | fs/9p/fid.h | 43 | ||||
-rw-r--r-- | fs/9p/mux.c | 1033 | ||||
-rw-r--r-- | fs/9p/mux.h | 55 | ||||
-rw-r--r-- | fs/9p/trans_fd.c | 308 | ||||
-rw-r--r-- | fs/9p/transport.h | 45 | ||||
-rw-r--r-- | fs/9p/v9fs.c | 288 | ||||
-rw-r--r-- | fs/9p/v9fs.h | 32 | ||||
-rw-r--r-- | fs/9p/v9fs_vfs.h | 6 | ||||
-rw-r--r-- | fs/9p/vfs_addr.c | 57 | ||||
-rw-r--r-- | fs/9p/vfs_dentry.c | 37 | ||||
-rw-r--r-- | fs/9p/vfs_dir.c | 155 | ||||
-rw-r--r-- | fs/9p/vfs_file.c | 160 | ||||
-rw-r--r-- | fs/9p/vfs_inode.c | 753 | ||||
-rw-r--r-- | fs/9p/vfs_super.c | 91 |
24 files changed, 552 insertions, 5074 deletions
diff --git a/fs/9p/9p.h b/fs/9p/9p.h deleted file mode 100644 index 94e2f92ab2e8..000000000000 --- a/fs/9p/9p.h +++ /dev/null | |||
@@ -1,375 +0,0 @@ | |||
1 | /* | ||
2 | * linux/fs/9p/9p.h | ||
3 | * | ||
4 | * 9P protocol definitions. | ||
5 | * | ||
6 | * Copyright (C) 2005 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 | /* Message Types */ | ||
28 | enum { | ||
29 | TVERSION = 100, | ||
30 | RVERSION, | ||
31 | TAUTH = 102, | ||
32 | RAUTH, | ||
33 | TATTACH = 104, | ||
34 | RATTACH, | ||
35 | TERROR = 106, | ||
36 | RERROR, | ||
37 | TFLUSH = 108, | ||
38 | RFLUSH, | ||
39 | TWALK = 110, | ||
40 | RWALK, | ||
41 | TOPEN = 112, | ||
42 | ROPEN, | ||
43 | TCREATE = 114, | ||
44 | RCREATE, | ||
45 | TREAD = 116, | ||
46 | RREAD, | ||
47 | TWRITE = 118, | ||
48 | RWRITE, | ||
49 | TCLUNK = 120, | ||
50 | RCLUNK, | ||
51 | TREMOVE = 122, | ||
52 | RREMOVE, | ||
53 | TSTAT = 124, | ||
54 | RSTAT, | ||
55 | TWSTAT = 126, | ||
56 | RWSTAT, | ||
57 | }; | ||
58 | |||
59 | /* modes */ | ||
60 | enum { | ||
61 | V9FS_OREAD = 0x00, | ||
62 | V9FS_OWRITE = 0x01, | ||
63 | V9FS_ORDWR = 0x02, | ||
64 | V9FS_OEXEC = 0x03, | ||
65 | V9FS_OEXCL = 0x04, | ||
66 | V9FS_OTRUNC = 0x10, | ||
67 | V9FS_OREXEC = 0x20, | ||
68 | V9FS_ORCLOSE = 0x40, | ||
69 | V9FS_OAPPEND = 0x80, | ||
70 | }; | ||
71 | |||
72 | /* permissions */ | ||
73 | enum { | ||
74 | V9FS_DMDIR = 0x80000000, | ||
75 | V9FS_DMAPPEND = 0x40000000, | ||
76 | V9FS_DMEXCL = 0x20000000, | ||
77 | V9FS_DMMOUNT = 0x10000000, | ||
78 | V9FS_DMAUTH = 0x08000000, | ||
79 | V9FS_DMTMP = 0x04000000, | ||
80 | V9FS_DMSYMLINK = 0x02000000, | ||
81 | V9FS_DMLINK = 0x01000000, | ||
82 | /* 9P2000.u extensions */ | ||
83 | V9FS_DMDEVICE = 0x00800000, | ||
84 | V9FS_DMNAMEDPIPE = 0x00200000, | ||
85 | V9FS_DMSOCKET = 0x00100000, | ||
86 | V9FS_DMSETUID = 0x00080000, | ||
87 | V9FS_DMSETGID = 0x00040000, | ||
88 | }; | ||
89 | |||
90 | /* qid.types */ | ||
91 | enum { | ||
92 | V9FS_QTDIR = 0x80, | ||
93 | V9FS_QTAPPEND = 0x40, | ||
94 | V9FS_QTEXCL = 0x20, | ||
95 | V9FS_QTMOUNT = 0x10, | ||
96 | V9FS_QTAUTH = 0x08, | ||
97 | V9FS_QTTMP = 0x04, | ||
98 | V9FS_QTSYMLINK = 0x02, | ||
99 | V9FS_QTLINK = 0x01, | ||
100 | V9FS_QTFILE = 0x00, | ||
101 | }; | ||
102 | |||
103 | #define V9FS_NOTAG (u16)(~0) | ||
104 | #define V9FS_NOFID (u32)(~0) | ||
105 | #define V9FS_MAXWELEM 16 | ||
106 | |||
107 | /* ample room for Twrite/Rread header (iounit) */ | ||
108 | #define V9FS_IOHDRSZ 24 | ||
109 | |||
110 | struct v9fs_str { | ||
111 | u16 len; | ||
112 | char *str; | ||
113 | }; | ||
114 | |||
115 | /* qids are the unique ID for a file (like an inode */ | ||
116 | struct v9fs_qid { | ||
117 | u8 type; | ||
118 | u32 version; | ||
119 | u64 path; | ||
120 | }; | ||
121 | |||
122 | /* Plan 9 file metadata (stat) structure */ | ||
123 | struct v9fs_stat { | ||
124 | u16 size; | ||
125 | u16 type; | ||
126 | u32 dev; | ||
127 | struct v9fs_qid qid; | ||
128 | u32 mode; | ||
129 | u32 atime; | ||
130 | u32 mtime; | ||
131 | u64 length; | ||
132 | struct v9fs_str name; | ||
133 | struct v9fs_str uid; | ||
134 | struct v9fs_str gid; | ||
135 | struct v9fs_str muid; | ||
136 | struct v9fs_str extension; /* 9p2000.u extensions */ | ||
137 | u32 n_uid; /* 9p2000.u extensions */ | ||
138 | u32 n_gid; /* 9p2000.u extensions */ | ||
139 | u32 n_muid; /* 9p2000.u extensions */ | ||
140 | }; | ||
141 | |||
142 | /* file metadata (stat) structure used to create Twstat message | ||
143 | The is similar to v9fs_stat, but the strings don't point to | ||
144 | the same memory block and should be freed separately | ||
145 | */ | ||
146 | struct v9fs_wstat { | ||
147 | u16 size; | ||
148 | u16 type; | ||
149 | u32 dev; | ||
150 | struct v9fs_qid qid; | ||
151 | u32 mode; | ||
152 | u32 atime; | ||
153 | u32 mtime; | ||
154 | u64 length; | ||
155 | char *name; | ||
156 | char *uid; | ||
157 | char *gid; | ||
158 | char *muid; | ||
159 | char *extension; /* 9p2000.u extensions */ | ||
160 | u32 n_uid; /* 9p2000.u extensions */ | ||
161 | u32 n_gid; /* 9p2000.u extensions */ | ||
162 | u32 n_muid; /* 9p2000.u extensions */ | ||
163 | }; | ||
164 | |||
165 | /* Structures for Protocol Operations */ | ||
166 | |||
167 | struct Tversion { | ||
168 | u32 msize; | ||
169 | struct v9fs_str version; | ||
170 | }; | ||
171 | |||
172 | struct Rversion { | ||
173 | u32 msize; | ||
174 | struct v9fs_str version; | ||
175 | }; | ||
176 | |||
177 | struct Tauth { | ||
178 | u32 afid; | ||
179 | struct v9fs_str uname; | ||
180 | struct v9fs_str aname; | ||
181 | }; | ||
182 | |||
183 | struct Rauth { | ||
184 | struct v9fs_qid qid; | ||
185 | }; | ||
186 | |||
187 | struct Rerror { | ||
188 | struct v9fs_str error; | ||
189 | u32 errno; /* 9p2000.u extension */ | ||
190 | }; | ||
191 | |||
192 | struct Tflush { | ||
193 | u16 oldtag; | ||
194 | }; | ||
195 | |||
196 | struct Rflush { | ||
197 | }; | ||
198 | |||
199 | struct Tattach { | ||
200 | u32 fid; | ||
201 | u32 afid; | ||
202 | struct v9fs_str uname; | ||
203 | struct v9fs_str aname; | ||
204 | }; | ||
205 | |||
206 | struct Rattach { | ||
207 | struct v9fs_qid qid; | ||
208 | }; | ||
209 | |||
210 | struct Twalk { | ||
211 | u32 fid; | ||
212 | u32 newfid; | ||
213 | u16 nwname; | ||
214 | struct v9fs_str wnames[16]; | ||
215 | }; | ||
216 | |||
217 | struct Rwalk { | ||
218 | u16 nwqid; | ||
219 | struct v9fs_qid wqids[16]; | ||
220 | }; | ||
221 | |||
222 | struct Topen { | ||
223 | u32 fid; | ||
224 | u8 mode; | ||
225 | }; | ||
226 | |||
227 | struct Ropen { | ||
228 | struct v9fs_qid qid; | ||
229 | u32 iounit; | ||
230 | }; | ||
231 | |||
232 | struct Tcreate { | ||
233 | u32 fid; | ||
234 | struct v9fs_str name; | ||
235 | u32 perm; | ||
236 | u8 mode; | ||
237 | struct v9fs_str extension; | ||
238 | }; | ||
239 | |||
240 | struct Rcreate { | ||
241 | struct v9fs_qid qid; | ||
242 | u32 iounit; | ||
243 | }; | ||
244 | |||
245 | struct Tread { | ||
246 | u32 fid; | ||
247 | u64 offset; | ||
248 | u32 count; | ||
249 | }; | ||
250 | |||
251 | struct Rread { | ||
252 | u32 count; | ||
253 | u8 *data; | ||
254 | }; | ||
255 | |||
256 | struct Twrite { | ||
257 | u32 fid; | ||
258 | u64 offset; | ||
259 | u32 count; | ||
260 | u8 *data; | ||
261 | }; | ||
262 | |||
263 | struct Rwrite { | ||
264 | u32 count; | ||
265 | }; | ||
266 | |||
267 | struct Tclunk { | ||
268 | u32 fid; | ||
269 | }; | ||
270 | |||
271 | struct Rclunk { | ||
272 | }; | ||
273 | |||
274 | struct Tremove { | ||
275 | u32 fid; | ||
276 | }; | ||
277 | |||
278 | struct Rremove { | ||
279 | }; | ||
280 | |||
281 | struct Tstat { | ||
282 | u32 fid; | ||
283 | }; | ||
284 | |||
285 | struct Rstat { | ||
286 | struct v9fs_stat stat; | ||
287 | }; | ||
288 | |||
289 | struct Twstat { | ||
290 | u32 fid; | ||
291 | struct v9fs_stat stat; | ||
292 | }; | ||
293 | |||
294 | struct Rwstat { | ||
295 | }; | ||
296 | |||
297 | /* | ||
298 | * fcall is the primary packet structure | ||
299 | * | ||
300 | */ | ||
301 | |||
302 | struct v9fs_fcall { | ||
303 | u32 size; | ||
304 | u8 id; | ||
305 | u16 tag; | ||
306 | void *sdata; | ||
307 | |||
308 | union { | ||
309 | struct Tversion tversion; | ||
310 | struct Rversion rversion; | ||
311 | struct Tauth tauth; | ||
312 | struct Rauth rauth; | ||
313 | struct Rerror rerror; | ||
314 | struct Tflush tflush; | ||
315 | struct Rflush rflush; | ||
316 | struct Tattach tattach; | ||
317 | struct Rattach rattach; | ||
318 | struct Twalk twalk; | ||
319 | struct Rwalk rwalk; | ||
320 | struct Topen topen; | ||
321 | struct Ropen ropen; | ||
322 | struct Tcreate tcreate; | ||
323 | struct Rcreate rcreate; | ||
324 | struct Tread tread; | ||
325 | struct Rread rread; | ||
326 | struct Twrite twrite; | ||
327 | struct Rwrite rwrite; | ||
328 | struct Tclunk tclunk; | ||
329 | struct Rclunk rclunk; | ||
330 | struct Tremove tremove; | ||
331 | struct Rremove rremove; | ||
332 | struct Tstat tstat; | ||
333 | struct Rstat rstat; | ||
334 | struct Twstat twstat; | ||
335 | struct Rwstat rwstat; | ||
336 | } params; | ||
337 | }; | ||
338 | |||
339 | #define PRINT_FCALL_ERROR(s, fcall) dprintk(DEBUG_ERROR, "%s: %.*s\n", s, \ | ||
340 | fcall?fcall->params.rerror.error.len:0, \ | ||
341 | fcall?fcall->params.rerror.error.str:""); | ||
342 | |||
343 | int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize, | ||
344 | char *version, struct v9fs_fcall **rcall); | ||
345 | |||
346 | int v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname, | ||
347 | u32 fid, u32 afid, struct v9fs_fcall **rcall); | ||
348 | |||
349 | int v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid); | ||
350 | |||
351 | int v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, | ||
352 | struct v9fs_fcall **rcall); | ||
353 | |||
354 | int v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid, | ||
355 | struct v9fs_wstat *wstat, struct v9fs_fcall **rcall); | ||
356 | |||
357 | int v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid, | ||
358 | char *name, struct v9fs_fcall **rcall); | ||
359 | |||
360 | int v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode, | ||
361 | struct v9fs_fcall **rcall); | ||
362 | |||
363 | int v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid, | ||
364 | struct v9fs_fcall **rcall); | ||
365 | |||
366 | int v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name, | ||
367 | u32 perm, u8 mode, char *extension, struct v9fs_fcall **rcall); | ||
368 | |||
369 | int v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, | ||
370 | u64 offset, u32 count, struct v9fs_fcall **rcall); | ||
371 | |||
372 | int v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset, | ||
373 | u32 count, const char __user * data, | ||
374 | struct v9fs_fcall **rcall); | ||
375 | int v9fs_printfcall(char *, int, struct v9fs_fcall *, int); | ||
diff --git a/fs/9p/Makefile b/fs/9p/Makefile index 87897f84dfb6..bc7f0d1551e6 100644 --- a/fs/9p/Makefile +++ b/fs/9p/Makefile | |||
@@ -1,18 +1,12 @@ | |||
1 | obj-$(CONFIG_9P_FS) := 9p.o | 1 | obj-$(CONFIG_9P_FS) := 9p.o |
2 | 2 | ||
3 | 9p-objs := \ | 3 | 9p-objs := \ |
4 | trans_fd.o \ | ||
5 | mux.o \ | ||
6 | fcall.o \ | ||
7 | conv.o \ | ||
8 | vfs_super.o \ | 4 | vfs_super.o \ |
9 | vfs_inode.o \ | 5 | vfs_inode.o \ |
10 | vfs_addr.o \ | 6 | vfs_addr.o \ |
11 | vfs_file.o \ | 7 | vfs_file.o \ |
12 | vfs_dir.o \ | 8 | vfs_dir.o \ |
13 | vfs_dentry.o \ | 9 | vfs_dentry.o \ |
14 | error.o \ | ||
15 | v9fs.o \ | 10 | v9fs.o \ |
16 | fid.o \ | 11 | fid.o \ |
17 | fcprint.o | ||
18 | 12 | ||
diff --git a/fs/9p/conv.c b/fs/9p/conv.c deleted file mode 100644 index a3ed571eee31..000000000000 --- a/fs/9p/conv.c +++ /dev/null | |||
@@ -1,845 +0,0 @@ | |||
1 | /* | ||
2 | * linux/fs/9p/conv.c | ||
3 | * | ||
4 | * 9P protocol conversion functions | ||
5 | * | ||
6 | * Copyright (C) 2004, 2005 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/sched.h> | ||
31 | #include <linux/idr.h> | ||
32 | #include <asm/uaccess.h> | ||
33 | #include "debug.h" | ||
34 | #include "v9fs.h" | ||
35 | #include "9p.h" | ||
36 | #include "conv.h" | ||
37 | |||
38 | /* | ||
39 | * Buffer to help with string parsing | ||
40 | */ | ||
41 | struct cbuf { | ||
42 | unsigned char *sp; | ||
43 | unsigned char *p; | ||
44 | unsigned char *ep; | ||
45 | }; | ||
46 | |||
47 | static inline void buf_init(struct cbuf *buf, void *data, int datalen) | ||
48 | { | ||
49 | buf->sp = buf->p = data; | ||
50 | buf->ep = data + datalen; | ||
51 | } | ||
52 | |||
53 | static inline int buf_check_overflow(struct cbuf *buf) | ||
54 | { | ||
55 | return buf->p > buf->ep; | ||
56 | } | ||
57 | |||
58 | static int buf_check_size(struct cbuf *buf, int len) | ||
59 | { | ||
60 | if (buf->p + len > buf->ep) { | ||
61 | if (buf->p < buf->ep) { | ||
62 | eprintk(KERN_ERR, "buffer overflow: want %d has %d\n", | ||
63 | len, (int)(buf->ep - buf->p)); | ||
64 | dump_stack(); | ||
65 | buf->p = buf->ep + 1; | ||
66 | } | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | return 1; | ||
72 | } | ||
73 | |||
74 | static void *buf_alloc(struct cbuf *buf, int len) | ||
75 | { | ||
76 | void *ret = NULL; | ||
77 | |||
78 | if (buf_check_size(buf, len)) { | ||
79 | ret = buf->p; | ||
80 | buf->p += len; | ||
81 | } | ||
82 | |||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | static void buf_put_int8(struct cbuf *buf, u8 val) | ||
87 | { | ||
88 | if (buf_check_size(buf, 1)) { | ||
89 | buf->p[0] = val; | ||
90 | buf->p++; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | static void buf_put_int16(struct cbuf *buf, u16 val) | ||
95 | { | ||
96 | if (buf_check_size(buf, 2)) { | ||
97 | *(__le16 *) buf->p = cpu_to_le16(val); | ||
98 | buf->p += 2; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | static void buf_put_int32(struct cbuf *buf, u32 val) | ||
103 | { | ||
104 | if (buf_check_size(buf, 4)) { | ||
105 | *(__le32 *)buf->p = cpu_to_le32(val); | ||
106 | buf->p += 4; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | static void buf_put_int64(struct cbuf *buf, u64 val) | ||
111 | { | ||
112 | if (buf_check_size(buf, 8)) { | ||
113 | *(__le64 *)buf->p = cpu_to_le64(val); | ||
114 | buf->p += 8; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen) | ||
119 | { | ||
120 | char *ret; | ||
121 | |||
122 | ret = NULL; | ||
123 | if (buf_check_size(buf, slen + 2)) { | ||
124 | buf_put_int16(buf, slen); | ||
125 | ret = buf->p; | ||
126 | memcpy(buf->p, s, slen); | ||
127 | buf->p += slen; | ||
128 | } | ||
129 | |||
130 | return ret; | ||
131 | } | ||
132 | |||
133 | static inline void buf_put_string(struct cbuf *buf, const char *s) | ||
134 | { | ||
135 | buf_put_stringn(buf, s, strlen(s)); | ||
136 | } | ||
137 | |||
138 | static u8 buf_get_int8(struct cbuf *buf) | ||
139 | { | ||
140 | u8 ret = 0; | ||
141 | |||
142 | if (buf_check_size(buf, 1)) { | ||
143 | ret = buf->p[0]; | ||
144 | buf->p++; | ||
145 | } | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | static u16 buf_get_int16(struct cbuf *buf) | ||
151 | { | ||
152 | u16 ret = 0; | ||
153 | |||
154 | if (buf_check_size(buf, 2)) { | ||
155 | ret = le16_to_cpu(*(__le16 *)buf->p); | ||
156 | buf->p += 2; | ||
157 | } | ||
158 | |||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | static u32 buf_get_int32(struct cbuf *buf) | ||
163 | { | ||
164 | u32 ret = 0; | ||
165 | |||
166 | if (buf_check_size(buf, 4)) { | ||
167 | ret = le32_to_cpu(*(__le32 *)buf->p); | ||
168 | buf->p += 4; | ||
169 | } | ||
170 | |||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | static u64 buf_get_int64(struct cbuf *buf) | ||
175 | { | ||
176 | u64 ret = 0; | ||
177 | |||
178 | if (buf_check_size(buf, 8)) { | ||
179 | ret = le64_to_cpu(*(__le64 *)buf->p); | ||
180 | buf->p += 8; | ||
181 | } | ||
182 | |||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | static void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr) | ||
187 | { | ||
188 | vstr->len = buf_get_int16(buf); | ||
189 | if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) { | ||
190 | vstr->str = buf->p; | ||
191 | buf->p += vstr->len; | ||
192 | } else { | ||
193 | vstr->len = 0; | ||
194 | vstr->str = NULL; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | static void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid) | ||
199 | { | ||
200 | qid->type = buf_get_int8(bufp); | ||
201 | qid->version = buf_get_int32(bufp); | ||
202 | qid->path = buf_get_int64(bufp); | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * v9fs_size_wstat - calculate the size of a variable length stat struct | ||
207 | * @stat: metadata (stat) structure | ||
208 | * @extended: non-zero if 9P2000.u | ||
209 | * | ||
210 | */ | ||
211 | |||
212 | static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended) | ||
213 | { | ||
214 | int size = 0; | ||
215 | |||
216 | if (wstat == NULL) { | ||
217 | eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n"); | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | size = /* 2 + *//* size[2] */ | ||
222 | 2 + /* type[2] */ | ||
223 | 4 + /* dev[4] */ | ||
224 | 1 + /* qid.type[1] */ | ||
225 | 4 + /* qid.vers[4] */ | ||
226 | 8 + /* qid.path[8] */ | ||
227 | 4 + /* mode[4] */ | ||
228 | 4 + /* atime[4] */ | ||
229 | 4 + /* mtime[4] */ | ||
230 | 8 + /* length[8] */ | ||
231 | 8; /* minimum sum of string lengths */ | ||
232 | |||
233 | if (wstat->name) | ||
234 | size += strlen(wstat->name); | ||
235 | if (wstat->uid) | ||
236 | size += strlen(wstat->uid); | ||
237 | if (wstat->gid) | ||
238 | size += strlen(wstat->gid); | ||
239 | if (wstat->muid) | ||
240 | size += strlen(wstat->muid); | ||
241 | |||
242 | if (extended) { | ||
243 | size += 4 + /* n_uid[4] */ | ||
244 | 4 + /* n_gid[4] */ | ||
245 | 4 + /* n_muid[4] */ | ||
246 | 2; /* string length of extension[4] */ | ||
247 | if (wstat->extension) | ||
248 | size += strlen(wstat->extension); | ||
249 | } | ||
250 | |||
251 | return size; | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * buf_get_stat - safely decode a recieved metadata (stat) structure | ||
256 | * @bufp: buffer to deserialize | ||
257 | * @stat: metadata (stat) structure | ||
258 | * @extended: non-zero if 9P2000.u | ||
259 | * | ||
260 | */ | ||
261 | |||
262 | static void | ||
263 | buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended) | ||
264 | { | ||
265 | stat->size = buf_get_int16(bufp); | ||
266 | stat->type = buf_get_int16(bufp); | ||
267 | stat->dev = buf_get_int32(bufp); | ||
268 | stat->qid.type = buf_get_int8(bufp); | ||
269 | stat->qid.version = buf_get_int32(bufp); | ||
270 | stat->qid.path = buf_get_int64(bufp); | ||
271 | stat->mode = buf_get_int32(bufp); | ||
272 | stat->atime = buf_get_int32(bufp); | ||
273 | stat->mtime = buf_get_int32(bufp); | ||
274 | stat->length = buf_get_int64(bufp); | ||
275 | buf_get_str(bufp, &stat->name); | ||
276 | buf_get_str(bufp, &stat->uid); | ||
277 | buf_get_str(bufp, &stat->gid); | ||
278 | buf_get_str(bufp, &stat->muid); | ||
279 | |||
280 | if (extended) { | ||
281 | buf_get_str(bufp, &stat->extension); | ||
282 | stat->n_uid = buf_get_int32(bufp); | ||
283 | stat->n_gid = buf_get_int32(bufp); | ||
284 | stat->n_muid = buf_get_int32(bufp); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * v9fs_deserialize_stat - decode a received metadata structure | ||
290 | * @buf: buffer to deserialize | ||
291 | * @buflen: length of received buffer | ||
292 | * @stat: metadata structure to decode into | ||
293 | * @extended: non-zero if 9P2000.u | ||
294 | * | ||
295 | * Note: stat will point to the buf region. | ||
296 | */ | ||
297 | |||
298 | int | ||
299 | v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat, | ||
300 | int extended) | ||
301 | { | ||
302 | struct cbuf buffer; | ||
303 | struct cbuf *bufp = &buffer; | ||
304 | unsigned char *p; | ||
305 | |||
306 | buf_init(bufp, buf, buflen); | ||
307 | p = bufp->p; | ||
308 | buf_get_stat(bufp, stat, extended); | ||
309 | |||
310 | if (buf_check_overflow(bufp)) | ||
311 | return 0; | ||
312 | else | ||
313 | return bufp->p - p; | ||
314 | } | ||
315 | |||
316 | /** | ||
317 | * deserialize_fcall - unmarshal a response | ||
318 | * @buf: recieved buffer | ||
319 | * @buflen: length of received buffer | ||
320 | * @rcall: fcall structure to populate | ||
321 | * @rcalllen: length of fcall structure to populate | ||
322 | * @extended: non-zero if 9P2000.u | ||
323 | * | ||
324 | */ | ||
325 | |||
326 | int | ||
327 | v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, | ||
328 | int extended) | ||
329 | { | ||
330 | |||
331 | struct cbuf buffer; | ||
332 | struct cbuf *bufp = &buffer; | ||
333 | int i = 0; | ||
334 | |||
335 | buf_init(bufp, buf, buflen); | ||
336 | |||
337 | rcall->size = buf_get_int32(bufp); | ||
338 | rcall->id = buf_get_int8(bufp); | ||
339 | rcall->tag = buf_get_int16(bufp); | ||
340 | |||
341 | dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id, | ||
342 | rcall->tag); | ||
343 | |||
344 | switch (rcall->id) { | ||
345 | default: | ||
346 | eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id); | ||
347 | return -EPROTO; | ||
348 | case RVERSION: | ||
349 | rcall->params.rversion.msize = buf_get_int32(bufp); | ||
350 | buf_get_str(bufp, &rcall->params.rversion.version); | ||
351 | break; | ||
352 | case RFLUSH: | ||
353 | break; | ||
354 | case RATTACH: | ||
355 | rcall->params.rattach.qid.type = buf_get_int8(bufp); | ||
356 | rcall->params.rattach.qid.version = buf_get_int32(bufp); | ||
357 | rcall->params.rattach.qid.path = buf_get_int64(bufp); | ||
358 | break; | ||
359 | case RWALK: | ||
360 | rcall->params.rwalk.nwqid = buf_get_int16(bufp); | ||
361 | if (rcall->params.rwalk.nwqid > V9FS_MAXWELEM) { | ||
362 | eprintk(KERN_ERR, "Rwalk with more than %d qids: %d\n", | ||
363 | V9FS_MAXWELEM, rcall->params.rwalk.nwqid); | ||
364 | return -EPROTO; | ||
365 | } | ||
366 | |||
367 | for (i = 0; i < rcall->params.rwalk.nwqid; i++) | ||
368 | buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]); | ||
369 | break; | ||
370 | case ROPEN: | ||
371 | buf_get_qid(bufp, &rcall->params.ropen.qid); | ||
372 | rcall->params.ropen.iounit = buf_get_int32(bufp); | ||
373 | break; | ||
374 | case RCREATE: | ||
375 | buf_get_qid(bufp, &rcall->params.rcreate.qid); | ||
376 | rcall->params.rcreate.iounit = buf_get_int32(bufp); | ||
377 | break; | ||
378 | case RREAD: | ||
379 | rcall->params.rread.count = buf_get_int32(bufp); | ||
380 | rcall->params.rread.data = bufp->p; | ||
381 | buf_check_size(bufp, rcall->params.rread.count); | ||
382 | break; | ||
383 | case RWRITE: | ||
384 | rcall->params.rwrite.count = buf_get_int32(bufp); | ||
385 | break; | ||
386 | case RCLUNK: | ||
387 | break; | ||
388 | case RREMOVE: | ||
389 | break; | ||
390 | case RSTAT: | ||
391 | buf_get_int16(bufp); | ||
392 | buf_get_stat(bufp, &rcall->params.rstat.stat, extended); | ||
393 | break; | ||
394 | case RWSTAT: | ||
395 | break; | ||
396 | case RERROR: | ||
397 | buf_get_str(bufp, &rcall->params.rerror.error); | ||
398 | if (extended) | ||
399 | rcall->params.rerror.errno = buf_get_int16(bufp); | ||
400 | break; | ||
401 | } | ||
402 | |||
403 | if (buf_check_overflow(bufp)) { | ||
404 | dprintk(DEBUG_ERROR, "buffer overflow\n"); | ||
405 | return -EIO; | ||
406 | } | ||
407 | |||
408 | return bufp->p - bufp->sp; | ||
409 | } | ||
410 | |||
411 | static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p) | ||
412 | { | ||
413 | *p = val; | ||
414 | buf_put_int8(bufp, val); | ||
415 | } | ||
416 | |||
417 | static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p) | ||
418 | { | ||
419 | *p = val; | ||
420 | buf_put_int16(bufp, val); | ||
421 | } | ||
422 | |||
423 | static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p) | ||
424 | { | ||
425 | *p = val; | ||
426 | buf_put_int32(bufp, val); | ||
427 | } | ||
428 | |||
429 | static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p) | ||
430 | { | ||
431 | *p = val; | ||
432 | buf_put_int64(bufp, val); | ||
433 | } | ||
434 | |||
435 | static void | ||
436 | v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str) | ||
437 | { | ||
438 | int len; | ||
439 | char *s; | ||
440 | |||
441 | if (data) | ||
442 | len = strlen(data); | ||
443 | else | ||
444 | len = 0; | ||
445 | |||
446 | s = buf_put_stringn(bufp, data, len); | ||
447 | if (str) { | ||
448 | str->len = len; | ||
449 | str->str = s; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | static int | ||
454 | v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count, | ||
455 | unsigned char **pdata) | ||
456 | { | ||
457 | *pdata = buf_alloc(bufp, count); | ||
458 | return copy_from_user(*pdata, data, count); | ||
459 | } | ||
460 | |||
461 | static void | ||
462 | v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat, | ||
463 | struct v9fs_stat *stat, int statsz, int extended) | ||
464 | { | ||
465 | v9fs_put_int16(bufp, statsz, &stat->size); | ||
466 | v9fs_put_int16(bufp, wstat->type, &stat->type); | ||
467 | v9fs_put_int32(bufp, wstat->dev, &stat->dev); | ||
468 | v9fs_put_int8(bufp, wstat->qid.type, &stat->qid.type); | ||
469 | v9fs_put_int32(bufp, wstat->qid.version, &stat->qid.version); | ||
470 | v9fs_put_int64(bufp, wstat->qid.path, &stat->qid.path); | ||
471 | v9fs_put_int32(bufp, wstat->mode, &stat->mode); | ||
472 | v9fs_put_int32(bufp, wstat->atime, &stat->atime); | ||
473 | v9fs_put_int32(bufp, wstat->mtime, &stat->mtime); | ||
474 | v9fs_put_int64(bufp, wstat->length, &stat->length); | ||
475 | |||
476 | v9fs_put_str(bufp, wstat->name, &stat->name); | ||
477 | v9fs_put_str(bufp, wstat->uid, &stat->uid); | ||
478 | v9fs_put_str(bufp, wstat->gid, &stat->gid); | ||
479 | v9fs_put_str(bufp, wstat->muid, &stat->muid); | ||
480 | |||
481 | if (extended) { | ||
482 | v9fs_put_str(bufp, wstat->extension, &stat->extension); | ||
483 | v9fs_put_int32(bufp, wstat->n_uid, &stat->n_uid); | ||
484 | v9fs_put_int32(bufp, wstat->n_gid, &stat->n_gid); | ||
485 | v9fs_put_int32(bufp, wstat->n_muid, &stat->n_muid); | ||
486 | } | ||
487 | } | ||
488 | |||
489 | static struct v9fs_fcall * | ||
490 | v9fs_create_common(struct cbuf *bufp, u32 size, u8 id) | ||
491 | { | ||
492 | struct v9fs_fcall *fc; | ||
493 | |||
494 | size += 4 + 1 + 2; /* size[4] id[1] tag[2] */ | ||
495 | fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL); | ||
496 | if (!fc) | ||
497 | return ERR_PTR(-ENOMEM); | ||
498 | |||
499 | fc->sdata = (char *)fc + sizeof(*fc); | ||
500 | |||
501 | buf_init(bufp, (char *)fc->sdata, size); | ||
502 | v9fs_put_int32(bufp, size, &fc->size); | ||
503 | v9fs_put_int8(bufp, id, &fc->id); | ||
504 | v9fs_put_int16(bufp, V9FS_NOTAG, &fc->tag); | ||
505 | |||
506 | return fc; | ||
507 | } | ||
508 | |||
509 | void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag) | ||
510 | { | ||
511 | fc->tag = tag; | ||
512 | *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag); | ||
513 | } | ||
514 | |||
515 | struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version) | ||
516 | { | ||
517 | int size; | ||
518 | struct v9fs_fcall *fc; | ||
519 | struct cbuf buffer; | ||
520 | struct cbuf *bufp = &buffer; | ||
521 | |||
522 | size = 4 + 2 + strlen(version); /* msize[4] version[s] */ | ||
523 | fc = v9fs_create_common(bufp, size, TVERSION); | ||
524 | if (IS_ERR(fc)) | ||
525 | goto error; | ||
526 | |||
527 | v9fs_put_int32(bufp, msize, &fc->params.tversion.msize); | ||
528 | v9fs_put_str(bufp, version, &fc->params.tversion.version); | ||
529 | |||
530 | if (buf_check_overflow(bufp)) { | ||
531 | kfree(fc); | ||
532 | fc = ERR_PTR(-ENOMEM); | ||
533 | } | ||
534 | error: | ||
535 | return fc; | ||
536 | } | ||
537 | |||
538 | #if 0 | ||
539 | struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname) | ||
540 | { | ||
541 | int size; | ||
542 | struct v9fs_fcall *fc; | ||
543 | struct cbuf buffer; | ||
544 | struct cbuf *bufp = &buffer; | ||
545 | |||
546 | size = 4 + 2 + strlen(uname) + 2 + strlen(aname); /* afid[4] uname[s] aname[s] */ | ||
547 | fc = v9fs_create_common(bufp, size, TAUTH); | ||
548 | if (IS_ERR(fc)) | ||
549 | goto error; | ||
550 | |||
551 | v9fs_put_int32(bufp, afid, &fc->params.tauth.afid); | ||
552 | v9fs_put_str(bufp, uname, &fc->params.tauth.uname); | ||
553 | v9fs_put_str(bufp, aname, &fc->params.tauth.aname); | ||
554 | |||
555 | if (buf_check_overflow(bufp)) { | ||
556 | kfree(fc); | ||
557 | fc = ERR_PTR(-ENOMEM); | ||
558 | } | ||
559 | error: | ||
560 | return fc; | ||
561 | } | ||
562 | #endif /* 0 */ | ||
563 | |||
564 | struct v9fs_fcall * | ||
565 | v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname) | ||
566 | { | ||
567 | int size; | ||
568 | struct v9fs_fcall *fc; | ||
569 | struct cbuf buffer; | ||
570 | struct cbuf *bufp = &buffer; | ||
571 | |||
572 | size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); /* fid[4] afid[4] uname[s] aname[s] */ | ||
573 | fc = v9fs_create_common(bufp, size, TATTACH); | ||
574 | if (IS_ERR(fc)) | ||
575 | goto error; | ||
576 | |||
577 | v9fs_put_int32(bufp, fid, &fc->params.tattach.fid); | ||
578 | v9fs_put_int32(bufp, afid, &fc->params.tattach.afid); | ||
579 | v9fs_put_str(bufp, uname, &fc->params.tattach.uname); | ||
580 | v9fs_put_str(bufp, aname, &fc->params.tattach.aname); | ||
581 | |||
582 | error: | ||
583 | return fc; | ||
584 | } | ||
585 | |||
586 | struct v9fs_fcall *v9fs_create_tflush(u16 oldtag) | ||
587 | { | ||
588 | int size; | ||
589 | struct v9fs_fcall *fc; | ||
590 | struct cbuf buffer; | ||
591 | struct cbuf *bufp = &buffer; | ||
592 | |||
593 | size = 2; /* oldtag[2] */ | ||
594 | fc = v9fs_create_common(bufp, size, TFLUSH); | ||
595 | if (IS_ERR(fc)) | ||
596 | goto error; | ||
597 | |||
598 | v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag); | ||
599 | |||
600 | if (buf_check_overflow(bufp)) { | ||
601 | kfree(fc); | ||
602 | fc = ERR_PTR(-ENOMEM); | ||
603 | } | ||
604 | error: | ||
605 | return fc; | ||
606 | } | ||
607 | |||
608 | struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname, | ||
609 | char **wnames) | ||
610 | { | ||
611 | int i, size; | ||
612 | struct v9fs_fcall *fc; | ||
613 | struct cbuf buffer; | ||
614 | struct cbuf *bufp = &buffer; | ||
615 | |||
616 | if (nwname > V9FS_MAXWELEM) { | ||
617 | dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM); | ||
618 | return NULL; | ||
619 | } | ||
620 | |||
621 | size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */ | ||
622 | for (i = 0; i < nwname; i++) { | ||
623 | size += 2 + strlen(wnames[i]); /* wname[s] */ | ||
624 | } | ||
625 | |||
626 | fc = v9fs_create_common(bufp, size, TWALK); | ||
627 | if (IS_ERR(fc)) | ||
628 | goto error; | ||
629 | |||
630 | v9fs_put_int32(bufp, fid, &fc->params.twalk.fid); | ||
631 | v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid); | ||
632 | v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname); | ||
633 | for (i = 0; i < nwname; i++) { | ||
634 | v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]); | ||
635 | } | ||
636 | |||
637 | if (buf_check_overflow(bufp)) { | ||
638 | kfree(fc); | ||
639 | fc = ERR_PTR(-ENOMEM); | ||
640 | } | ||
641 | error: | ||
642 | return fc; | ||
643 | } | ||
644 | |||
645 | struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode) | ||
646 | { | ||
647 | int size; | ||
648 | struct v9fs_fcall *fc; | ||
649 | struct cbuf buffer; | ||
650 | struct cbuf *bufp = &buffer; | ||
651 | |||
652 | size = 4 + 1; /* fid[4] mode[1] */ | ||
653 | fc = v9fs_create_common(bufp, size, TOPEN); | ||
654 | if (IS_ERR(fc)) | ||
655 | goto error; | ||
656 | |||
657 | v9fs_put_int32(bufp, fid, &fc->params.topen.fid); | ||
658 | v9fs_put_int8(bufp, mode, &fc->params.topen.mode); | ||
659 | |||
660 | if (buf_check_overflow(bufp)) { | ||
661 | kfree(fc); | ||
662 | fc = ERR_PTR(-ENOMEM); | ||
663 | } | ||
664 | error: | ||
665 | return fc; | ||
666 | } | ||
667 | |||
668 | struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode, | ||
669 | char *extension, int extended) | ||
670 | { | ||
671 | int size; | ||
672 | struct v9fs_fcall *fc; | ||
673 | struct cbuf buffer; | ||
674 | struct cbuf *bufp = &buffer; | ||
675 | |||
676 | size = 4 + 2 + strlen(name) + 4 + 1; /* fid[4] name[s] perm[4] mode[1] */ | ||
677 | if (extended) { | ||
678 | size += 2 + /* extension[s] */ | ||
679 | (extension == NULL ? 0 : strlen(extension)); | ||
680 | } | ||
681 | |||
682 | fc = v9fs_create_common(bufp, size, TCREATE); | ||
683 | if (IS_ERR(fc)) | ||
684 | goto error; | ||
685 | |||
686 | v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid); | ||
687 | v9fs_put_str(bufp, name, &fc->params.tcreate.name); | ||
688 | v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm); | ||
689 | v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode); | ||
690 | if (extended) | ||
691 | v9fs_put_str(bufp, extension, &fc->params.tcreate.extension); | ||
692 | |||
693 | if (buf_check_overflow(bufp)) { | ||
694 | kfree(fc); | ||
695 | fc = ERR_PTR(-ENOMEM); | ||
696 | } | ||
697 | error: | ||
698 | return fc; | ||
699 | } | ||
700 | |||
701 | struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count) | ||
702 | { | ||
703 | int size; | ||
704 | struct v9fs_fcall *fc; | ||
705 | struct cbuf buffer; | ||
706 | struct cbuf *bufp = &buffer; | ||
707 | |||
708 | size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */ | ||
709 | fc = v9fs_create_common(bufp, size, TREAD); | ||
710 | if (IS_ERR(fc)) | ||
711 | goto error; | ||
712 | |||
713 | v9fs_put_int32(bufp, fid, &fc->params.tread.fid); | ||
714 | v9fs_put_int64(bufp, offset, &fc->params.tread.offset); | ||
715 | v9fs_put_int32(bufp, count, &fc->params.tread.count); | ||
716 | |||
717 | if (buf_check_overflow(bufp)) { | ||
718 | kfree(fc); | ||
719 | fc = ERR_PTR(-ENOMEM); | ||
720 | } | ||
721 | error: | ||
722 | return fc; | ||
723 | } | ||
724 | |||
725 | struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count, | ||
726 | const char __user * data) | ||
727 | { | ||
728 | int size, err; | ||
729 | struct v9fs_fcall *fc; | ||
730 | struct cbuf buffer; | ||
731 | struct cbuf *bufp = &buffer; | ||
732 | |||
733 | size = 4 + 8 + 4 + count; /* fid[4] offset[8] count[4] data[count] */ | ||
734 | fc = v9fs_create_common(bufp, size, TWRITE); | ||
735 | if (IS_ERR(fc)) | ||
736 | goto error; | ||
737 | |||
738 | v9fs_put_int32(bufp, fid, &fc->params.twrite.fid); | ||
739 | v9fs_put_int64(bufp, offset, &fc->params.twrite.offset); | ||
740 | v9fs_put_int32(bufp, count, &fc->params.twrite.count); | ||
741 | err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data); | ||
742 | if (err) { | ||
743 | kfree(fc); | ||
744 | fc = ERR_PTR(err); | ||
745 | } | ||
746 | |||
747 | if (buf_check_overflow(bufp)) { | ||
748 | kfree(fc); | ||
749 | fc = ERR_PTR(-ENOMEM); | ||
750 | } | ||
751 | error: | ||
752 | return fc; | ||
753 | } | ||
754 | |||
755 | struct v9fs_fcall *v9fs_create_tclunk(u32 fid) | ||
756 | { | ||
757 | int size; | ||
758 | struct v9fs_fcall *fc; | ||
759 | struct cbuf buffer; | ||
760 | struct cbuf *bufp = &buffer; | ||
761 | |||
762 | size = 4; /* fid[4] */ | ||
763 | fc = v9fs_create_common(bufp, size, TCLUNK); | ||
764 | if (IS_ERR(fc)) | ||
765 | goto error; | ||
766 | |||
767 | v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid); | ||
768 | |||
769 | if (buf_check_overflow(bufp)) { | ||
770 | kfree(fc); | ||
771 | fc = ERR_PTR(-ENOMEM); | ||
772 | } | ||
773 | error: | ||
774 | return fc; | ||
775 | } | ||
776 | |||
777 | struct v9fs_fcall *v9fs_create_tremove(u32 fid) | ||
778 | { | ||
779 | int size; | ||
780 | struct v9fs_fcall *fc; | ||
781 | struct cbuf buffer; | ||
782 | struct cbuf *bufp = &buffer; | ||
783 | |||
784 | size = 4; /* fid[4] */ | ||
785 | fc = v9fs_create_common(bufp, size, TREMOVE); | ||
786 | if (IS_ERR(fc)) | ||
787 | goto error; | ||
788 | |||
789 | v9fs_put_int32(bufp, fid, &fc->params.tremove.fid); | ||
790 | |||
791 | if (buf_check_overflow(bufp)) { | ||
792 | kfree(fc); | ||
793 | fc = ERR_PTR(-ENOMEM); | ||
794 | } | ||
795 | error: | ||
796 | return fc; | ||
797 | } | ||
798 | |||
799 | struct v9fs_fcall *v9fs_create_tstat(u32 fid) | ||
800 | { | ||
801 | int size; | ||
802 | struct v9fs_fcall *fc; | ||
803 | struct cbuf buffer; | ||
804 | struct cbuf *bufp = &buffer; | ||
805 | |||
806 | size = 4; /* fid[4] */ | ||
807 | fc = v9fs_create_common(bufp, size, TSTAT); | ||
808 | if (IS_ERR(fc)) | ||
809 | goto error; | ||
810 | |||
811 | v9fs_put_int32(bufp, fid, &fc->params.tstat.fid); | ||
812 | |||
813 | if (buf_check_overflow(bufp)) { | ||
814 | kfree(fc); | ||
815 | fc = ERR_PTR(-ENOMEM); | ||
816 | } | ||
817 | error: | ||
818 | return fc; | ||
819 | } | ||
820 | |||
821 | struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat, | ||
822 | int extended) | ||
823 | { | ||
824 | int size, statsz; | ||
825 | struct v9fs_fcall *fc; | ||
826 | struct cbuf buffer; | ||
827 | struct cbuf *bufp = &buffer; | ||
828 | |||
829 | statsz = v9fs_size_wstat(wstat, extended); | ||
830 | size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */ | ||
831 | fc = v9fs_create_common(bufp, size, TWSTAT); | ||
832 | if (IS_ERR(fc)) | ||
833 | goto error; | ||
834 | |||
835 | v9fs_put_int32(bufp, fid, &fc->params.twstat.fid); | ||
836 | buf_put_int16(bufp, statsz + 2); | ||
837 | v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended); | ||
838 | |||
839 | if (buf_check_overflow(bufp)) { | ||
840 | kfree(fc); | ||
841 | fc = ERR_PTR(-ENOMEM); | ||
842 | } | ||
843 | error: | ||
844 | return fc; | ||
845 | } | ||
diff --git a/fs/9p/conv.h b/fs/9p/conv.h deleted file mode 100644 index dd5b6b1b610f..000000000000 --- a/fs/9p/conv.h +++ /dev/null | |||
@@ -1,50 +0,0 @@ | |||
1 | /* | ||
2 | * linux/fs/9p/conv.h | ||
3 | * | ||
4 | * 9P protocol conversion definitions. | ||
5 | * | ||
6 | * Copyright (C) 2005 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 | int v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat, | ||
28 | int extended); | ||
29 | int v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, | ||
30 | int extended); | ||
31 | |||
32 | void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag); | ||
33 | |||
34 | struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version); | ||
35 | struct v9fs_fcall *v9fs_create_tattach(u32 fid, u32 afid, char *uname, | ||
36 | char *aname); | ||
37 | struct v9fs_fcall *v9fs_create_tflush(u16 oldtag); | ||
38 | struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname, | ||
39 | char **wnames); | ||
40 | struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode); | ||
41 | struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode, | ||
42 | char *extension, int extended); | ||
43 | struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count); | ||
44 | struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count, | ||
45 | const char __user *data); | ||
46 | struct v9fs_fcall *v9fs_create_tclunk(u32 fid); | ||
47 | struct v9fs_fcall *v9fs_create_tremove(u32 fid); | ||
48 | struct v9fs_fcall *v9fs_create_tstat(u32 fid); | ||
49 | struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat, | ||
50 | int extended); | ||
diff --git a/fs/9p/debug.h b/fs/9p/debug.h deleted file mode 100644 index 4228c0bb3c32..000000000000 --- a/fs/9p/debug.h +++ /dev/null | |||
@@ -1,77 +0,0 @@ | |||
1 | /* | ||
2 | * linux/fs/9p/debug.h - V9FS Debug Definitions | ||
3 | * | ||
4 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | ||
5 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 | ||
9 | * as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to: | ||
18 | * Free Software Foundation | ||
19 | * 51 Franklin Street, Fifth Floor | ||
20 | * Boston, MA 02111-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #define DEBUG_ERROR (1<<0) | ||
25 | #define DEBUG_CURRENT (1<<1) | ||
26 | #define DEBUG_9P (1<<2) | ||
27 | #define DEBUG_VFS (1<<3) | ||
28 | #define DEBUG_CONV (1<<4) | ||
29 | #define DEBUG_MUX (1<<5) | ||
30 | #define DEBUG_TRANS (1<<6) | ||
31 | #define DEBUG_SLABS (1<<7) | ||
32 | #define DEBUG_FCALL (1<<8) | ||
33 | |||
34 | #define DEBUG_DUMP_PKT 0 | ||
35 | |||
36 | extern int v9fs_debug_level; | ||
37 | |||
38 | #define dprintk(level, format, arg...) \ | ||
39 | do { \ | ||
40 | if((v9fs_debug_level & level)==level) \ | ||
41 | printk(KERN_NOTICE "-- %s (%d): " \ | ||
42 | format , __FUNCTION__, current->pid , ## arg); \ | ||
43 | } while(0) | ||
44 | |||
45 | #define eprintk(level, format, arg...) \ | ||
46 | do { \ | ||
47 | printk(level "v9fs: %s (%d): " \ | ||
48 | format , __FUNCTION__, current->pid , ## arg); \ | ||
49 | } while(0) | ||
50 | |||
51 | #if DEBUG_DUMP_PKT | ||
52 | static inline void dump_data(const unsigned char *data, unsigned int datalen) | ||
53 | { | ||
54 | int i, n; | ||
55 | char buf[5*8]; | ||
56 | |||
57 | n = 0; | ||
58 | i = 0; | ||
59 | while (i < datalen) { | ||
60 | n += snprintf(buf+n, sizeof(buf)-n, "%02x", data[i++]); | ||
61 | if (i%4 == 0) | ||
62 | n += snprintf(buf+n, sizeof(buf)-n, " "); | ||
63 | |||
64 | if (i%16 == 0) { | ||
65 | dprintk(DEBUG_ERROR, "%s\n", buf); | ||
66 | n = 0; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | dprintk(DEBUG_ERROR, "%s\n", buf); | ||
71 | } | ||
72 | #else /* DEBUG_DUMP_PKT */ | ||
73 | static inline void dump_data(const unsigned char *data, unsigned int datalen) | ||
74 | { | ||
75 | |||
76 | } | ||
77 | #endif /* DEBUG_DUMP_PKT */ | ||
diff --git a/fs/9p/error.c b/fs/9p/error.c deleted file mode 100644 index 0d7fa4e08812..000000000000 --- a/fs/9p/error.c +++ /dev/null | |||
@@ -1,93 +0,0 @@ | |||
1 | /* | ||
2 | * linux/fs/9p/error.c | ||
3 | * | ||
4 | * Error string handling | ||
5 | * | ||
6 | * Plan 9 uses error strings, Unix uses error numbers. These functions | ||
7 | * try to help manage that and provide for dynamically adding error | ||
8 | * mappings. | ||
9 | * | ||
10 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | ||
11 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License version 2 | ||
15 | * as published by the Free Software Foundation. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to: | ||
24 | * Free Software Foundation | ||
25 | * 51 Franklin Street, Fifth Floor | ||
26 | * Boston, MA 02111-1301 USA | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | #include <linux/module.h> | ||
31 | |||
32 | #include <linux/list.h> | ||
33 | #include <linux/jhash.h> | ||
34 | |||
35 | #include "debug.h" | ||
36 | #include "error.h" | ||
37 | |||
38 | /** | ||
39 | * v9fs_error_init - preload | ||
40 | * @errstr: error string | ||
41 | * | ||
42 | */ | ||
43 | |||
44 | int v9fs_error_init(void) | ||
45 | { | ||
46 | struct errormap *c; | ||
47 | int bucket; | ||
48 | |||
49 | /* initialize hash table */ | ||
50 | for (bucket = 0; bucket < ERRHASHSZ; bucket++) | ||
51 | INIT_HLIST_HEAD(&hash_errmap[bucket]); | ||
52 | |||
53 | /* load initial error map into hash table */ | ||
54 | for (c = errmap; c->name != NULL; c++) { | ||
55 | c->namelen = strlen(c->name); | ||
56 | bucket = jhash(c->name, c->namelen, 0) % ERRHASHSZ; | ||
57 | INIT_HLIST_NODE(&c->list); | ||
58 | hlist_add_head(&c->list, &hash_errmap[bucket]); | ||
59 | } | ||
60 | |||
61 | return 1; | ||
62 | } | ||
63 | |||
64 | /** | ||
65 | * errstr2errno - convert error string to error number | ||
66 | * @errstr: error string | ||
67 | * | ||
68 | */ | ||
69 | |||
70 | int v9fs_errstr2errno(char *errstr, int len) | ||
71 | { | ||
72 | int errno = 0; | ||
73 | struct hlist_node *p = NULL; | ||
74 | struct errormap *c = NULL; | ||
75 | int bucket = jhash(errstr, len, 0) % ERRHASHSZ; | ||
76 | |||
77 | hlist_for_each_entry(c, p, &hash_errmap[bucket], list) { | ||
78 | if (c->namelen==len && !memcmp(c->name, errstr, len)) { | ||
79 | errno = c->val; | ||
80 | break; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | if (errno == 0) { | ||
85 | /* TODO: if error isn't found, add it dynamically */ | ||
86 | errstr[len] = 0; | ||
87 | printk(KERN_ERR "%s: errstr :%s: not found\n", __FUNCTION__, | ||
88 | errstr); | ||
89 | errno = 1; | ||
90 | } | ||
91 | |||
92 | return -errno; | ||
93 | } | ||
diff --git a/fs/9p/error.h b/fs/9p/error.h deleted file mode 100644 index 5f3ca522b316..000000000000 --- a/fs/9p/error.h +++ /dev/null | |||
@@ -1,177 +0,0 @@ | |||
1 | /* | ||
2 | * linux/fs/9p/error.h | ||
3 | * | ||
4 | * Huge Nasty Error Table | ||
5 | * | ||
6 | * Plan 9 uses error strings, Unix uses error numbers. This table tries to | ||
7 | * match UNIX strings and Plan 9 strings to unix error numbers. It is used | ||
8 | * to preload the dynamic error table which can also track user-specific error | ||
9 | * strings. | ||
10 | * | ||
11 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | ||
12 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License version 2 | ||
16 | * as published by the Free Software Foundation. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to: | ||
25 | * Free Software Foundation | ||
26 | * 51 Franklin Street, Fifth Floor | ||
27 | * Boston, MA 02111-1301 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/errno.h> | ||
32 | #include <asm/errno.h> | ||
33 | |||
34 | struct errormap { | ||
35 | char *name; | ||
36 | int val; | ||
37 | |||
38 | int namelen; | ||
39 | struct hlist_node list; | ||
40 | }; | ||
41 | |||
42 | #define ERRHASHSZ 32 | ||
43 | static struct hlist_head hash_errmap[ERRHASHSZ]; | ||
44 | |||
45 | /* FixMe - reduce to a reasonable size */ | ||
46 | static struct errormap errmap[] = { | ||
47 | {"Operation not permitted", EPERM}, | ||
48 | {"wstat prohibited", EPERM}, | ||
49 | {"No such file or directory", ENOENT}, | ||
50 | {"directory entry not found", ENOENT}, | ||
51 | {"file not found", ENOENT}, | ||
52 | {"Interrupted system call", EINTR}, | ||
53 | {"Input/output error", EIO}, | ||
54 | {"No such device or address", ENXIO}, | ||
55 | {"Argument list too long", E2BIG}, | ||
56 | {"Bad file descriptor", EBADF}, | ||
57 | {"Resource temporarily unavailable", EAGAIN}, | ||
58 | {"Cannot allocate memory", ENOMEM}, | ||
59 | {"Permission denied", EACCES}, | ||
60 | {"Bad address", EFAULT}, | ||
61 | {"Block device required", ENOTBLK}, | ||
62 | {"Device or resource busy", EBUSY}, | ||
63 | {"File exists", EEXIST}, | ||
64 | {"Invalid cross-device link", EXDEV}, | ||
65 | {"No such device", ENODEV}, | ||
66 | {"Not a directory", ENOTDIR}, | ||
67 | {"Is a directory", EISDIR}, | ||
68 | {"Invalid argument", EINVAL}, | ||
69 | {"Too many open files in system", ENFILE}, | ||
70 | {"Too many open files", EMFILE}, | ||
71 | {"Text file busy", ETXTBSY}, | ||
72 | {"File too large", EFBIG}, | ||
73 | {"No space left on device", ENOSPC}, | ||
74 | {"Illegal seek", ESPIPE}, | ||
75 | {"Read-only file system", EROFS}, | ||
76 | {"Too many links", EMLINK}, | ||
77 | {"Broken pipe", EPIPE}, | ||
78 | {"Numerical argument out of domain", EDOM}, | ||
79 | {"Numerical result out of range", ERANGE}, | ||
80 | {"Resource deadlock avoided", EDEADLK}, | ||
81 | {"File name too long", ENAMETOOLONG}, | ||
82 | {"No locks available", ENOLCK}, | ||
83 | {"Function not implemented", ENOSYS}, | ||
84 | {"Directory not empty", ENOTEMPTY}, | ||
85 | {"Too many levels of symbolic links", ELOOP}, | ||
86 | {"No message of desired type", ENOMSG}, | ||
87 | {"Identifier removed", EIDRM}, | ||
88 | {"No data available", ENODATA}, | ||
89 | {"Machine is not on the network", ENONET}, | ||
90 | {"Package not installed", ENOPKG}, | ||
91 | {"Object is remote", EREMOTE}, | ||
92 | {"Link has been severed", ENOLINK}, | ||
93 | {"Communication error on send", ECOMM}, | ||
94 | {"Protocol error", EPROTO}, | ||
95 | {"Bad message", EBADMSG}, | ||
96 | {"File descriptor in bad state", EBADFD}, | ||
97 | {"Streams pipe error", ESTRPIPE}, | ||
98 | {"Too many users", EUSERS}, | ||
99 | {"Socket operation on non-socket", ENOTSOCK}, | ||
100 | {"Message too long", EMSGSIZE}, | ||
101 | {"Protocol not available", ENOPROTOOPT}, | ||
102 | {"Protocol not supported", EPROTONOSUPPORT}, | ||
103 | {"Socket type not supported", ESOCKTNOSUPPORT}, | ||
104 | {"Operation not supported", EOPNOTSUPP}, | ||
105 | {"Protocol family not supported", EPFNOSUPPORT}, | ||
106 | {"Network is down", ENETDOWN}, | ||
107 | {"Network is unreachable", ENETUNREACH}, | ||
108 | {"Network dropped connection on reset", ENETRESET}, | ||
109 | {"Software caused connection abort", ECONNABORTED}, | ||
110 | {"Connection reset by peer", ECONNRESET}, | ||
111 | {"No buffer space available", ENOBUFS}, | ||
112 | {"Transport endpoint is already connected", EISCONN}, | ||
113 | {"Transport endpoint is not connected", ENOTCONN}, | ||
114 | {"Cannot send after transport endpoint shutdown", ESHUTDOWN}, | ||
115 | {"Connection timed out", ETIMEDOUT}, | ||
116 | {"Connection refused", ECONNREFUSED}, | ||
117 | {"Host is down", EHOSTDOWN}, | ||
118 | {"No route to host", EHOSTUNREACH}, | ||
119 | {"Operation already in progress", EALREADY}, | ||
120 | {"Operation now in progress", EINPROGRESS}, | ||
121 | {"Is a named type file", EISNAM}, | ||
122 | {"Remote I/O error", EREMOTEIO}, | ||
123 | {"Disk quota exceeded", EDQUOT}, | ||
124 | /* errors from fossil, vacfs, and u9fs */ | ||
125 | {"fid unknown or out of range", EBADF}, | ||
126 | {"permission denied", EACCES}, | ||
127 | {"file does not exist", ENOENT}, | ||
128 | {"authentication failed", ECONNREFUSED}, | ||
129 | {"bad offset in directory read", ESPIPE}, | ||
130 | {"bad use of fid", EBADF}, | ||
131 | {"wstat can't convert between files and directories", EPERM}, | ||
132 | {"directory is not empty", ENOTEMPTY}, | ||
133 | {"file exists", EEXIST}, | ||
134 | {"file already exists", EEXIST}, | ||
135 | {"file or directory already exists", EEXIST}, | ||
136 | {"fid already in use", EBADF}, | ||
137 | {"file in use", ETXTBSY}, | ||
138 | {"i/o error", EIO}, | ||
139 | {"file already open for I/O", ETXTBSY}, | ||
140 | {"illegal mode", EINVAL}, | ||
141 | {"illegal name", ENAMETOOLONG}, | ||
142 | {"not a directory", ENOTDIR}, | ||
143 | {"not a member of proposed group", EPERM}, | ||
144 | {"not owner", EACCES}, | ||
145 | {"only owner can change group in wstat", EACCES}, | ||
146 | {"read only file system", EROFS}, | ||
147 | {"no access to special file", EPERM}, | ||
148 | {"i/o count too large", EIO}, | ||
149 | {"unknown group", EINVAL}, | ||
150 | {"unknown user", EINVAL}, | ||
151 | {"bogus wstat buffer", EPROTO}, | ||
152 | {"exclusive use file already open", EAGAIN}, | ||
153 | {"corrupted directory entry", EIO}, | ||
154 | {"corrupted file entry", EIO}, | ||
155 | {"corrupted block label", EIO}, | ||
156 | {"corrupted meta data", EIO}, | ||
157 | {"illegal offset", EINVAL}, | ||
158 | {"illegal path element", ENOENT}, | ||
159 | {"root of file system is corrupted", EIO}, | ||
160 | {"corrupted super block", EIO}, | ||
161 | {"protocol botch", EPROTO}, | ||
162 | {"file system is full", ENOSPC}, | ||
163 | {"file is in use", EAGAIN}, | ||
164 | {"directory entry is not allocated", ENOENT}, | ||
165 | {"file is read only", EROFS}, | ||
166 | {"file has been removed", EIDRM}, | ||
167 | {"only support truncation to zero length", EPERM}, | ||
168 | {"cannot remove root", EPERM}, | ||
169 | {"file too big", EFBIG}, | ||
170 | {"venti i/o error", EIO}, | ||
171 | /* these are not errors */ | ||
172 | {"u9fs rhostsauth: no authentication required", 0}, | ||
173 | {"u9fs authnone: no authentication required", 0}, | ||
174 | {NULL, -1} | ||
175 | }; | ||
176 | |||
177 | extern int v9fs_error_init(void); | ||
diff --git a/fs/9p/fcall.c b/fs/9p/fcall.c deleted file mode 100644 index dc336a67592f..000000000000 --- a/fs/9p/fcall.c +++ /dev/null | |||
@@ -1,427 +0,0 @@ | |||
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/sched.h> | ||
31 | #include <linux/idr.h> | ||
32 | |||
33 | #include "debug.h" | ||
34 | #include "v9fs.h" | ||
35 | #include "9p.h" | ||
36 | #include "conv.h" | ||
37 | #include "mux.h" | ||
38 | |||
39 | /** | ||
40 | * v9fs_t_version - negotiate protocol parameters with sever | ||
41 | * @v9ses: 9P2000 session information | ||
42 | * @msize: requested max size packet | ||
43 | * @version: requested version.extension string | ||
44 | * @fcall: pointer to response fcall pointer | ||
45 | * | ||
46 | */ | ||
47 | |||
48 | int | ||
49 | v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize, | ||
50 | char *version, struct v9fs_fcall **rcp) | ||
51 | { | ||
52 | int ret; | ||
53 | struct v9fs_fcall *tc; | ||
54 | |||
55 | dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version); | ||
56 | tc = v9fs_create_tversion(msize, version); | ||
57 | |||
58 | if (!IS_ERR(tc)) { | ||
59 | ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); | ||
60 | kfree(tc); | ||
61 | } else | ||
62 | ret = PTR_ERR(tc); | ||
63 | |||
64 | return ret; | ||
65 | } | ||
66 | |||
67 | /** | ||
68 | * v9fs_t_attach - mount the server | ||
69 | * @v9ses: 9P2000 session information | ||
70 | * @uname: user name doing the attach | ||
71 | * @aname: remote name being attached to | ||
72 | * @fid: mount fid to attatch to root node | ||
73 | * @afid: authentication fid (in this case result key) | ||
74 | * @fcall: pointer to response fcall pointer | ||
75 | * | ||
76 | */ | ||
77 | |||
78 | int | ||
79 | v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname, | ||
80 | u32 fid, u32 afid, struct v9fs_fcall **rcp) | ||
81 | { | ||
82 | int ret; | ||
83 | struct v9fs_fcall* tc; | ||
84 | |||
85 | dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname, | ||
86 | aname, fid, afid); | ||
87 | |||
88 | tc = v9fs_create_tattach(fid, afid, uname, aname); | ||
89 | if (!IS_ERR(tc)) { | ||
90 | ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); | ||
91 | kfree(tc); | ||
92 | } else | ||
93 | ret = PTR_ERR(tc); | ||
94 | |||
95 | return ret; | ||
96 | } | ||
97 | |||
98 | static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc, | ||
99 | struct v9fs_fcall *rc, int err) | ||
100 | { | ||
101 | int fid, id; | ||
102 | struct v9fs_session_info *v9ses; | ||
103 | |||
104 | id = 0; | ||
105 | fid = tc->params.tclunk.fid; | ||
106 | if (rc) | ||
107 | id = rc->id; | ||
108 | |||
109 | kfree(tc); | ||
110 | kfree(rc); | ||
111 | if (id == RCLUNK) { | ||
112 | v9ses = a; | ||
113 | v9fs_put_idpool(fid, &v9ses->fidpool); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | /** | ||
118 | * v9fs_t_clunk - release a fid (finish a transaction) | ||
119 | * @v9ses: 9P2000 session information | ||
120 | * @fid: fid to release | ||
121 | * @fcall: pointer to response fcall pointer | ||
122 | * | ||
123 | */ | ||
124 | |||
125 | int | ||
126 | v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid) | ||
127 | { | ||
128 | int ret; | ||
129 | struct v9fs_fcall *tc, *rc; | ||
130 | |||
131 | dprintk(DEBUG_9P, "fid %d\n", fid); | ||
132 | |||
133 | rc = NULL; | ||
134 | tc = v9fs_create_tclunk(fid); | ||
135 | if (!IS_ERR(tc)) | ||
136 | ret = v9fs_mux_rpc(v9ses->mux, tc, &rc); | ||
137 | else | ||
138 | ret = PTR_ERR(tc); | ||
139 | |||
140 | if (ret) | ||
141 | dprintk(DEBUG_ERROR, "failed fid %d err %d\n", fid, ret); | ||
142 | |||
143 | v9fs_t_clunk_cb(v9ses, tc, rc, ret); | ||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | #if 0 | ||
148 | /** | ||
149 | * v9fs_v9fs_t_flush - flush a pending transaction | ||
150 | * @v9ses: 9P2000 session information | ||
151 | * @tag: tag to release | ||
152 | * | ||
153 | */ | ||
154 | int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag) | ||
155 | { | ||
156 | int ret; | ||
157 | struct v9fs_fcall *tc; | ||
158 | |||
159 | dprintk(DEBUG_9P, "oldtag %d\n", oldtag); | ||
160 | |||
161 | tc = v9fs_create_tflush(oldtag); | ||
162 | if (!IS_ERR(tc)) { | ||
163 | ret = v9fs_mux_rpc(v9ses->mux, tc, NULL); | ||
164 | kfree(tc); | ||
165 | } else | ||
166 | ret = PTR_ERR(tc); | ||
167 | |||
168 | return ret; | ||
169 | } | ||
170 | #endif | ||
171 | |||
172 | /** | ||
173 | * v9fs_t_stat - read a file's meta-data | ||
174 | * @v9ses: 9P2000 session information | ||
175 | * @fid: fid pointing to file or directory to get info about | ||
176 | * @fcall: pointer to response fcall | ||
177 | * | ||
178 | */ | ||
179 | |||
180 | int | ||
181 | v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **rcp) | ||
182 | { | ||
183 | int ret; | ||
184 | struct v9fs_fcall *tc; | ||
185 | |||
186 | dprintk(DEBUG_9P, "fid %d\n", fid); | ||
187 | |||
188 | ret = -ENOMEM; | ||
189 | tc = v9fs_create_tstat(fid); | ||
190 | if (!IS_ERR(tc)) { | ||
191 | ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); | ||
192 | kfree(tc); | ||
193 | } else | ||
194 | ret = PTR_ERR(tc); | ||
195 | |||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * v9fs_t_wstat - write a file's meta-data | ||
201 | * @v9ses: 9P2000 session information | ||
202 | * @fid: fid pointing to file or directory to write info about | ||
203 | * @stat: metadata | ||
204 | * @fcall: pointer to response fcall | ||
205 | * | ||
206 | */ | ||
207 | |||
208 | int | ||
209 | v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid, | ||
210 | struct v9fs_wstat *wstat, struct v9fs_fcall **rcp) | ||
211 | { | ||
212 | int ret; | ||
213 | struct v9fs_fcall *tc; | ||
214 | |||
215 | dprintk(DEBUG_9P, "fid %d\n", fid); | ||
216 | |||
217 | tc = v9fs_create_twstat(fid, wstat, v9ses->extended); | ||
218 | if (!IS_ERR(tc)) { | ||
219 | ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); | ||
220 | kfree(tc); | ||
221 | } else | ||
222 | ret = PTR_ERR(tc); | ||
223 | |||
224 | return ret; | ||
225 | } | ||
226 | |||
227 | /** | ||
228 | * v9fs_t_walk - walk a fid to a new file or directory | ||
229 | * @v9ses: 9P2000 session information | ||
230 | * @fid: fid to walk | ||
231 | * @newfid: new fid (for clone operations) | ||
232 | * @name: path to walk fid to | ||
233 | * @fcall: pointer to response fcall | ||
234 | * | ||
235 | */ | ||
236 | |||
237 | /* TODO: support multiple walk */ | ||
238 | |||
239 | int | ||
240 | v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid, | ||
241 | char *name, struct v9fs_fcall **rcp) | ||
242 | { | ||
243 | int ret; | ||
244 | struct v9fs_fcall *tc; | ||
245 | int nwname; | ||
246 | |||
247 | dprintk(DEBUG_9P, "fid %d newfid %d wname '%s'\n", fid, newfid, name); | ||
248 | |||
249 | if (name) | ||
250 | nwname = 1; | ||
251 | else | ||
252 | nwname = 0; | ||
253 | |||
254 | tc = v9fs_create_twalk(fid, newfid, nwname, &name); | ||
255 | if (!IS_ERR(tc)) { | ||
256 | ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); | ||
257 | kfree(tc); | ||
258 | } else | ||
259 | ret = PTR_ERR(tc); | ||
260 | |||
261 | return ret; | ||
262 | } | ||
263 | |||
264 | /** | ||
265 | * v9fs_t_open - open a file | ||
266 | * | ||
267 | * @v9ses - 9P2000 session information | ||
268 | * @fid - fid to open | ||
269 | * @mode - mode to open file (R, RW, etc) | ||
270 | * @fcall - pointer to response fcall | ||
271 | * | ||
272 | */ | ||
273 | |||
274 | int | ||
275 | v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode, | ||
276 | struct v9fs_fcall **rcp) | ||
277 | { | ||
278 | int ret; | ||
279 | struct v9fs_fcall *tc; | ||
280 | |||
281 | dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode); | ||
282 | |||
283 | tc = v9fs_create_topen(fid, mode); | ||
284 | if (!IS_ERR(tc)) { | ||
285 | ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); | ||
286 | kfree(tc); | ||
287 | } else | ||
288 | ret = PTR_ERR(tc); | ||
289 | |||
290 | return ret; | ||
291 | } | ||
292 | |||
293 | /** | ||
294 | * v9fs_t_remove - remove a file or directory | ||
295 | * @v9ses: 9P2000 session information | ||
296 | * @fid: fid to remove | ||
297 | * @fcall: pointer to response fcall | ||
298 | * | ||
299 | */ | ||
300 | |||
301 | int | ||
302 | v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid, | ||
303 | struct v9fs_fcall **rcp) | ||
304 | { | ||
305 | int ret; | ||
306 | struct v9fs_fcall *tc; | ||
307 | |||
308 | dprintk(DEBUG_9P, "fid %d\n", fid); | ||
309 | |||
310 | tc = v9fs_create_tremove(fid); | ||
311 | if (!IS_ERR(tc)) { | ||
312 | ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); | ||
313 | kfree(tc); | ||
314 | } else | ||
315 | ret = PTR_ERR(tc); | ||
316 | |||
317 | return ret; | ||
318 | } | ||
319 | |||
320 | /** | ||
321 | * v9fs_t_create - create a file or directory | ||
322 | * @v9ses: 9P2000 session information | ||
323 | * @fid: fid to create | ||
324 | * @name: name of the file or directory to create | ||
325 | * @perm: permissions to create with | ||
326 | * @mode: mode to open file (R, RW, etc) | ||
327 | * @fcall: pointer to response fcall | ||
328 | * | ||
329 | */ | ||
330 | |||
331 | int | ||
332 | v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name, u32 perm, | ||
333 | u8 mode, char *extension, struct v9fs_fcall **rcp) | ||
334 | { | ||
335 | int ret; | ||
336 | struct v9fs_fcall *tc; | ||
337 | |||
338 | dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n", | ||
339 | fid, name, perm, mode); | ||
340 | |||
341 | tc = v9fs_create_tcreate(fid, name, perm, mode, extension, | ||
342 | v9ses->extended); | ||
343 | |||
344 | if (!IS_ERR(tc)) { | ||
345 | ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); | ||
346 | kfree(tc); | ||
347 | } else | ||
348 | ret = PTR_ERR(tc); | ||
349 | |||
350 | return ret; | ||
351 | } | ||
352 | |||
353 | /** | ||
354 | * v9fs_t_read - read data | ||
355 | * @v9ses: 9P2000 session information | ||
356 | * @fid: fid to read from | ||
357 | * @offset: offset to start read at | ||
358 | * @count: how many bytes to read | ||
359 | * @fcall: pointer to response fcall (with data) | ||
360 | * | ||
361 | */ | ||
362 | |||
363 | int | ||
364 | v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset, | ||
365 | u32 count, struct v9fs_fcall **rcp) | ||
366 | { | ||
367 | int ret; | ||
368 | struct v9fs_fcall *tc, *rc; | ||
369 | |||
370 | dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid, | ||
371 | (long long unsigned) offset, count); | ||
372 | |||
373 | tc = v9fs_create_tread(fid, offset, count); | ||
374 | if (!IS_ERR(tc)) { | ||
375 | ret = v9fs_mux_rpc(v9ses->mux, tc, &rc); | ||
376 | if (!ret) | ||
377 | ret = rc->params.rread.count; | ||
378 | if (rcp) | ||
379 | *rcp = rc; | ||
380 | else | ||
381 | kfree(rc); | ||
382 | |||
383 | kfree(tc); | ||
384 | } else | ||
385 | ret = PTR_ERR(tc); | ||
386 | |||
387 | return ret; | ||
388 | } | ||
389 | |||
390 | /** | ||
391 | * v9fs_t_write - write data | ||
392 | * @v9ses: 9P2000 session information | ||
393 | * @fid: fid to write to | ||
394 | * @offset: offset to start write at | ||
395 | * @count: how many bytes to write | ||
396 | * @fcall: pointer to response fcall | ||
397 | * | ||
398 | */ | ||
399 | |||
400 | int | ||
401 | v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset, u32 count, | ||
402 | const char __user *data, struct v9fs_fcall **rcp) | ||
403 | { | ||
404 | int ret; | ||
405 | struct v9fs_fcall *tc, *rc; | ||
406 | |||
407 | dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid, | ||
408 | (long long unsigned) offset, count); | ||
409 | |||
410 | tc = v9fs_create_twrite(fid, offset, count, data); | ||
411 | if (!IS_ERR(tc)) { | ||
412 | ret = v9fs_mux_rpc(v9ses->mux, tc, &rc); | ||
413 | |||
414 | if (!ret) | ||
415 | ret = rc->params.rwrite.count; | ||
416 | if (rcp) | ||
417 | *rcp = rc; | ||
418 | else | ||
419 | kfree(rc); | ||
420 | |||
421 | kfree(tc); | ||
422 | } else | ||
423 | ret = PTR_ERR(tc); | ||
424 | |||
425 | return ret; | ||
426 | } | ||
427 | |||
diff --git a/fs/9p/fcprint.c b/fs/9p/fcprint.c deleted file mode 100644 index 34b96114a28d..000000000000 --- a/fs/9p/fcprint.c +++ /dev/null | |||
@@ -1,345 +0,0 @@ | |||
1 | /* | ||
2 | * linux/fs/9p/fcprint.c | ||
3 | * | ||
4 | * Print 9P call. | ||
5 | * | ||
6 | * Copyright (C) 2005 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 | #include <linux/module.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/fs.h> | ||
27 | #include <linux/idr.h> | ||
28 | |||
29 | #include "debug.h" | ||
30 | #include "v9fs.h" | ||
31 | #include "9p.h" | ||
32 | #include "mux.h" | ||
33 | |||
34 | static int | ||
35 | v9fs_printqid(char *buf, int buflen, struct v9fs_qid *q) | ||
36 | { | ||
37 | int n; | ||
38 | char b[10]; | ||
39 | |||
40 | n = 0; | ||
41 | if (q->type & V9FS_QTDIR) | ||
42 | b[n++] = 'd'; | ||
43 | if (q->type & V9FS_QTAPPEND) | ||
44 | b[n++] = 'a'; | ||
45 | if (q->type & V9FS_QTAUTH) | ||
46 | b[n++] = 'A'; | ||
47 | if (q->type & V9FS_QTEXCL) | ||
48 | b[n++] = 'l'; | ||
49 | if (q->type & V9FS_QTTMP) | ||
50 | b[n++] = 't'; | ||
51 | if (q->type & V9FS_QTSYMLINK) | ||
52 | b[n++] = 'L'; | ||
53 | b[n] = '\0'; | ||
54 | |||
55 | return scnprintf(buf, buflen, "(%.16llx %x %s)", (long long int) q->path, | ||
56 | q->version, b); | ||
57 | } | ||
58 | |||
59 | static int | ||
60 | v9fs_printperm(char *buf, int buflen, int perm) | ||
61 | { | ||
62 | int n; | ||
63 | char b[15]; | ||
64 | |||
65 | n = 0; | ||
66 | if (perm & V9FS_DMDIR) | ||
67 | b[n++] = 'd'; | ||
68 | if (perm & V9FS_DMAPPEND) | ||
69 | b[n++] = 'a'; | ||
70 | if (perm & V9FS_DMAUTH) | ||
71 | b[n++] = 'A'; | ||
72 | if (perm & V9FS_DMEXCL) | ||
73 | b[n++] = 'l'; | ||
74 | if (perm & V9FS_DMTMP) | ||
75 | b[n++] = 't'; | ||
76 | if (perm & V9FS_DMDEVICE) | ||
77 | b[n++] = 'D'; | ||
78 | if (perm & V9FS_DMSOCKET) | ||
79 | b[n++] = 'S'; | ||
80 | if (perm & V9FS_DMNAMEDPIPE) | ||
81 | b[n++] = 'P'; | ||
82 | if (perm & V9FS_DMSYMLINK) | ||
83 | b[n++] = 'L'; | ||
84 | b[n] = '\0'; | ||
85 | |||
86 | return scnprintf(buf, buflen, "%s%03o", b, perm&077); | ||
87 | } | ||
88 | |||
89 | static int | ||
90 | v9fs_printstat(char *buf, int buflen, struct v9fs_stat *st, int extended) | ||
91 | { | ||
92 | int n; | ||
93 | |||
94 | n = scnprintf(buf, buflen, "'%.*s' '%.*s'", st->name.len, | ||
95 | st->name.str, st->uid.len, st->uid.str); | ||
96 | if (extended) | ||
97 | n += scnprintf(buf+n, buflen-n, "(%d)", st->n_uid); | ||
98 | |||
99 | n += scnprintf(buf+n, buflen-n, " '%.*s'", st->gid.len, st->gid.str); | ||
100 | if (extended) | ||
101 | n += scnprintf(buf+n, buflen-n, "(%d)", st->n_gid); | ||
102 | |||
103 | n += scnprintf(buf+n, buflen-n, " '%.*s'", st->muid.len, st->muid.str); | ||
104 | if (extended) | ||
105 | n += scnprintf(buf+n, buflen-n, "(%d)", st->n_muid); | ||
106 | |||
107 | n += scnprintf(buf+n, buflen-n, " q "); | ||
108 | n += v9fs_printqid(buf+n, buflen-n, &st->qid); | ||
109 | n += scnprintf(buf+n, buflen-n, " m "); | ||
110 | n += v9fs_printperm(buf+n, buflen-n, st->mode); | ||
111 | n += scnprintf(buf+n, buflen-n, " at %d mt %d l %lld", | ||
112 | st->atime, st->mtime, (long long int) st->length); | ||
113 | |||
114 | if (extended) | ||
115 | n += scnprintf(buf+n, buflen-n, " ext '%.*s'", | ||
116 | st->extension.len, st->extension.str); | ||
117 | |||
118 | return n; | ||
119 | } | ||
120 | |||
121 | static int | ||
122 | v9fs_dumpdata(char *buf, int buflen, u8 *data, int datalen) | ||
123 | { | ||
124 | int i, n; | ||
125 | |||
126 | i = n = 0; | ||
127 | while (i < datalen) { | ||
128 | n += scnprintf(buf + n, buflen - n, "%02x", data[i]); | ||
129 | if (i%4 == 3) | ||
130 | n += scnprintf(buf + n, buflen - n, " "); | ||
131 | if (i%32 == 31) | ||
132 | n += scnprintf(buf + n, buflen - n, "\n"); | ||
133 | |||
134 | i++; | ||
135 | } | ||
136 | n += scnprintf(buf + n, buflen - n, "\n"); | ||
137 | |||
138 | return n; | ||
139 | } | ||
140 | |||
141 | static int | ||
142 | v9fs_printdata(char *buf, int buflen, u8 *data, int datalen) | ||
143 | { | ||
144 | return v9fs_dumpdata(buf, buflen, data, datalen<16?datalen:16); | ||
145 | } | ||
146 | |||
147 | int | ||
148 | v9fs_printfcall(char *buf, int buflen, struct v9fs_fcall *fc, int extended) | ||
149 | { | ||
150 | int i, ret, type, tag; | ||
151 | |||
152 | if (!fc) | ||
153 | return scnprintf(buf, buflen, "<NULL>"); | ||
154 | |||
155 | type = fc->id; | ||
156 | tag = fc->tag; | ||
157 | |||
158 | ret = 0; | ||
159 | switch (type) { | ||
160 | case TVERSION: | ||
161 | ret += scnprintf(buf+ret, buflen-ret, | ||
162 | "Tversion tag %u msize %u version '%.*s'", tag, | ||
163 | fc->params.tversion.msize, fc->params.tversion.version.len, | ||
164 | fc->params.tversion.version.str); | ||
165 | break; | ||
166 | |||
167 | case RVERSION: | ||
168 | ret += scnprintf(buf+ret, buflen-ret, | ||
169 | "Rversion tag %u msize %u version '%.*s'", tag, | ||
170 | fc->params.rversion.msize, fc->params.rversion.version.len, | ||
171 | fc->params.rversion.version.str); | ||
172 | break; | ||
173 | |||
174 | case TAUTH: | ||
175 | ret += scnprintf(buf+ret, buflen-ret, | ||
176 | "Tauth tag %u afid %d uname '%.*s' aname '%.*s'", tag, | ||
177 | fc->params.tauth.afid, fc->params.tauth.uname.len, | ||
178 | fc->params.tauth.uname.str, fc->params.tauth.aname.len, | ||
179 | fc->params.tauth.aname.str); | ||
180 | break; | ||
181 | |||
182 | case RAUTH: | ||
183 | ret += scnprintf(buf+ret, buflen-ret, "Rauth tag %u qid ", tag); | ||
184 | v9fs_printqid(buf+ret, buflen-ret, &fc->params.rauth.qid); | ||
185 | break; | ||
186 | |||
187 | case TATTACH: | ||
188 | ret += scnprintf(buf+ret, buflen-ret, | ||
189 | "Tattach tag %u fid %d afid %d uname '%.*s' aname '%.*s'", | ||
190 | tag, fc->params.tattach.fid, fc->params.tattach.afid, | ||
191 | fc->params.tattach.uname.len, fc->params.tattach.uname.str, | ||
192 | fc->params.tattach.aname.len, fc->params.tattach.aname.str); | ||
193 | break; | ||
194 | |||
195 | case RATTACH: | ||
196 | ret += scnprintf(buf+ret, buflen-ret, "Rattach tag %u qid ", tag); | ||
197 | v9fs_printqid(buf+ret, buflen-ret, &fc->params.rattach.qid); | ||
198 | break; | ||
199 | |||
200 | case RERROR: | ||
201 | ret += scnprintf(buf+ret, buflen-ret, "Rerror tag %u ename '%.*s'", | ||
202 | tag, fc->params.rerror.error.len, | ||
203 | fc->params.rerror.error.str); | ||
204 | if (extended) | ||
205 | ret += scnprintf(buf+ret, buflen-ret, " ecode %d\n", | ||
206 | fc->params.rerror.errno); | ||
207 | break; | ||
208 | |||
209 | case TFLUSH: | ||
210 | ret += scnprintf(buf+ret, buflen-ret, "Tflush tag %u oldtag %u", | ||
211 | tag, fc->params.tflush.oldtag); | ||
212 | break; | ||
213 | |||
214 | case RFLUSH: | ||
215 | ret += scnprintf(buf+ret, buflen-ret, "Rflush tag %u", tag); | ||
216 | break; | ||
217 | |||
218 | case TWALK: | ||
219 | ret += scnprintf(buf+ret, buflen-ret, | ||
220 | "Twalk tag %u fid %d newfid %d nwname %d", tag, | ||
221 | fc->params.twalk.fid, fc->params.twalk.newfid, | ||
222 | fc->params.twalk.nwname); | ||
223 | for(i = 0; i < fc->params.twalk.nwname; i++) | ||
224 | ret += scnprintf(buf+ret, buflen-ret," '%.*s'", | ||
225 | fc->params.twalk.wnames[i].len, | ||
226 | fc->params.twalk.wnames[i].str); | ||
227 | break; | ||
228 | |||
229 | case RWALK: | ||
230 | ret += scnprintf(buf+ret, buflen-ret, "Rwalk tag %u nwqid %d", | ||
231 | tag, fc->params.rwalk.nwqid); | ||
232 | for(i = 0; i < fc->params.rwalk.nwqid; i++) | ||
233 | ret += v9fs_printqid(buf+ret, buflen-ret, | ||
234 | &fc->params.rwalk.wqids[i]); | ||
235 | break; | ||
236 | |||
237 | case TOPEN: | ||
238 | ret += scnprintf(buf+ret, buflen-ret, | ||
239 | "Topen tag %u fid %d mode %d", tag, | ||
240 | fc->params.topen.fid, fc->params.topen.mode); | ||
241 | break; | ||
242 | |||
243 | case ROPEN: | ||
244 | ret += scnprintf(buf+ret, buflen-ret, "Ropen tag %u", tag); | ||
245 | ret += v9fs_printqid(buf+ret, buflen-ret, &fc->params.ropen.qid); | ||
246 | ret += scnprintf(buf+ret, buflen-ret," iounit %d", | ||
247 | fc->params.ropen.iounit); | ||
248 | break; | ||
249 | |||
250 | case TCREATE: | ||
251 | ret += scnprintf(buf+ret, buflen-ret, | ||
252 | "Tcreate tag %u fid %d name '%.*s' perm ", tag, | ||
253 | fc->params.tcreate.fid, fc->params.tcreate.name.len, | ||
254 | fc->params.tcreate.name.str); | ||
255 | |||
256 | ret += v9fs_printperm(buf+ret, buflen-ret, fc->params.tcreate.perm); | ||
257 | ret += scnprintf(buf+ret, buflen-ret, " mode %d", | ||
258 | fc->params.tcreate.mode); | ||
259 | break; | ||
260 | |||
261 | case RCREATE: | ||
262 | ret += scnprintf(buf+ret, buflen-ret, "Rcreate tag %u", tag); | ||
263 | ret += v9fs_printqid(buf+ret, buflen-ret, &fc->params.rcreate.qid); | ||
264 | ret += scnprintf(buf+ret, buflen-ret, " iounit %d", | ||
265 | fc->params.rcreate.iounit); | ||
266 | break; | ||
267 | |||
268 | case TREAD: | ||
269 | ret += scnprintf(buf+ret, buflen-ret, | ||
270 | "Tread tag %u fid %d offset %lld count %u", tag, | ||
271 | fc->params.tread.fid, | ||
272 | (long long int) fc->params.tread.offset, | ||
273 | fc->params.tread.count); | ||
274 | break; | ||
275 | |||
276 | case RREAD: | ||
277 | ret += scnprintf(buf+ret, buflen-ret, | ||
278 | "Rread tag %u count %u data ", tag, | ||
279 | fc->params.rread.count); | ||
280 | ret += v9fs_printdata(buf+ret, buflen-ret, fc->params.rread.data, | ||
281 | fc->params.rread.count); | ||
282 | break; | ||
283 | |||
284 | case TWRITE: | ||
285 | ret += scnprintf(buf+ret, buflen-ret, | ||
286 | "Twrite tag %u fid %d offset %lld count %u data ", | ||
287 | tag, fc->params.twrite.fid, | ||
288 | (long long int) fc->params.twrite.offset, | ||
289 | fc->params.twrite.count); | ||
290 | ret += v9fs_printdata(buf+ret, buflen-ret, fc->params.twrite.data, | ||
291 | fc->params.twrite.count); | ||
292 | break; | ||
293 | |||
294 | case RWRITE: | ||
295 | ret += scnprintf(buf+ret, buflen-ret, "Rwrite tag %u count %u", | ||
296 | tag, fc->params.rwrite.count); | ||
297 | break; | ||
298 | |||
299 | case TCLUNK: | ||
300 | ret += scnprintf(buf+ret, buflen-ret, "Tclunk tag %u fid %d", | ||
301 | tag, fc->params.tclunk.fid); | ||
302 | break; | ||
303 | |||
304 | case RCLUNK: | ||
305 | ret += scnprintf(buf+ret, buflen-ret, "Rclunk tag %u", tag); | ||
306 | break; | ||
307 | |||
308 | case TREMOVE: | ||
309 | ret += scnprintf(buf+ret, buflen-ret, "Tremove tag %u fid %d", | ||
310 | tag, fc->params.tremove.fid); | ||
311 | break; | ||
312 | |||
313 | case RREMOVE: | ||
314 | ret += scnprintf(buf+ret, buflen-ret, "Rremove tag %u", tag); | ||
315 | break; | ||
316 | |||
317 | case TSTAT: | ||
318 | ret += scnprintf(buf+ret, buflen-ret, "Tstat tag %u fid %d", | ||
319 | tag, fc->params.tstat.fid); | ||
320 | break; | ||
321 | |||
322 | case RSTAT: | ||
323 | ret += scnprintf(buf+ret, buflen-ret, "Rstat tag %u ", tag); | ||
324 | ret += v9fs_printstat(buf+ret, buflen-ret, &fc->params.rstat.stat, | ||
325 | extended); | ||
326 | break; | ||
327 | |||
328 | case TWSTAT: | ||
329 | ret += scnprintf(buf+ret, buflen-ret, "Twstat tag %u fid %d ", | ||
330 | tag, fc->params.twstat.fid); | ||
331 | ret += v9fs_printstat(buf+ret, buflen-ret, &fc->params.twstat.stat, | ||
332 | extended); | ||
333 | break; | ||
334 | |||
335 | case RWSTAT: | ||
336 | ret += scnprintf(buf+ret, buflen-ret, "Rwstat tag %u", tag); | ||
337 | break; | ||
338 | |||
339 | default: | ||
340 | ret += scnprintf(buf+ret, buflen-ret, "unknown type %d", type); | ||
341 | break; | ||
342 | } | ||
343 | |||
344 | return ret; | ||
345 | } | ||
diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 90419715c7e9..08fa320b7e6d 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c | |||
@@ -26,10 +26,10 @@ | |||
26 | #include <linux/sched.h> | 26 | #include <linux/sched.h> |
27 | #include <linux/idr.h> | 27 | #include <linux/idr.h> |
28 | #include <asm/semaphore.h> | 28 | #include <asm/semaphore.h> |
29 | #include <net/9p/9p.h> | ||
30 | #include <net/9p/client.h> | ||
29 | 31 | ||
30 | #include "debug.h" | ||
31 | #include "v9fs.h" | 32 | #include "v9fs.h" |
32 | #include "9p.h" | ||
33 | #include "v9fs_vfs.h" | 33 | #include "v9fs_vfs.h" |
34 | #include "fid.h" | 34 | #include "fid.h" |
35 | 35 | ||
@@ -40,67 +40,29 @@ | |||
40 | * | 40 | * |
41 | */ | 41 | */ |
42 | 42 | ||
43 | int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry) | 43 | int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid) |
44 | { | 44 | { |
45 | struct list_head *fid_list = (struct list_head *)dentry->d_fsdata; | 45 | struct v9fs_dentry *dent; |
46 | dprintk(DEBUG_9P, "fid %d (%p) dentry %s (%p)\n", fid->fid, fid, | ||
47 | dentry->d_iname, dentry); | ||
48 | if (dentry->d_fsdata == NULL) { | ||
49 | dentry->d_fsdata = | ||
50 | kmalloc(sizeof(struct list_head), GFP_KERNEL); | ||
51 | if (dentry->d_fsdata == NULL) { | ||
52 | dprintk(DEBUG_ERROR, "Out of memory\n"); | ||
53 | return -ENOMEM; | ||
54 | } | ||
55 | fid_list = (struct list_head *)dentry->d_fsdata; | ||
56 | INIT_LIST_HEAD(fid_list); /* Initialize list head */ | ||
57 | } | ||
58 | 46 | ||
59 | fid->uid = current->uid; | 47 | P9_DPRINTK(P9_DEBUG_VFS, "fid %d dentry %s\n", |
60 | list_add(&fid->list, fid_list); | 48 | fid->fid, dentry->d_iname); |
61 | return 0; | ||
62 | } | ||
63 | 49 | ||
64 | /** | 50 | dent = dentry->d_fsdata; |
65 | * v9fs_fid_create - allocate a FID structure | 51 | if (!dent) { |
66 | * @dentry - dentry to link newly created fid to | 52 | dent = kmalloc(sizeof(struct v9fs_dentry), GFP_KERNEL); |
67 | * | 53 | if (!dent) |
68 | */ | 54 | return -ENOMEM; |
69 | |||
70 | struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *v9ses, int fid) | ||
71 | { | ||
72 | struct v9fs_fid *new; | ||
73 | 55 | ||
74 | dprintk(DEBUG_9P, "fid create fid %d\n", fid); | 56 | spin_lock_init(&dent->lock); |
75 | new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); | 57 | INIT_LIST_HEAD(&dent->fidlist); |
76 | if (new == NULL) { | 58 | dentry->d_fsdata = dent; |
77 | dprintk(DEBUG_ERROR, "Out of Memory\n"); | ||
78 | return ERR_PTR(-ENOMEM); | ||
79 | } | 59 | } |
80 | 60 | ||
81 | new->fid = fid; | 61 | spin_lock(&dent->lock); |
82 | new->v9ses = v9ses; | 62 | list_add(&fid->dlist, &dent->fidlist); |
83 | new->fidopen = 0; | 63 | spin_unlock(&dent->lock); |
84 | new->fidclunked = 0; | ||
85 | new->iounit = 0; | ||
86 | new->rdir_pos = 0; | ||
87 | new->rdir_fcall = NULL; | ||
88 | init_MUTEX(&new->lock); | ||
89 | INIT_LIST_HEAD(&new->list); | ||
90 | |||
91 | return new; | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * v9fs_fid_destroy - deallocate a FID structure | ||
96 | * @fid: fid to destroy | ||
97 | * | ||
98 | */ | ||
99 | 64 | ||
100 | void v9fs_fid_destroy(struct v9fs_fid *fid) | 65 | return 0; |
101 | { | ||
102 | list_del(&fid->list); | ||
103 | kfree(fid); | ||
104 | } | 66 | } |
105 | 67 | ||
106 | /** | 68 | /** |
@@ -114,30 +76,42 @@ void v9fs_fid_destroy(struct v9fs_fid *fid) | |||
114 | * | 76 | * |
115 | */ | 77 | */ |
116 | 78 | ||
117 | struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry) | 79 | struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) |
118 | { | 80 | { |
119 | struct list_head *fid_list = (struct list_head *)dentry->d_fsdata; | 81 | struct v9fs_dentry *dent; |
120 | struct v9fs_fid *return_fid = NULL; | 82 | struct p9_fid *fid; |
121 | 83 | ||
122 | dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry); | 84 | P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); |
123 | 85 | dent = dentry->d_fsdata; | |
124 | if (fid_list) | 86 | if (dent) |
125 | return_fid = list_entry(fid_list->next, struct v9fs_fid, list); | 87 | fid = list_entry(dent->fidlist.next, struct p9_fid, dlist); |
88 | else | ||
89 | fid = ERR_PTR(-EBADF); | ||
90 | |||
91 | P9_DPRINTK(P9_DEBUG_VFS, " fid: %p\n", fid); | ||
92 | return fid; | ||
93 | } | ||
126 | 94 | ||
127 | if (!return_fid) { | 95 | struct p9_fid *v9fs_fid_lookup_remove(struct dentry *dentry) |
128 | dprintk(DEBUG_ERROR, "Couldn't find a fid in dentry\n"); | 96 | { |
129 | return_fid = ERR_PTR(-EBADF); | 97 | struct p9_fid *fid; |
98 | struct v9fs_dentry *dent; | ||
99 | |||
100 | dent = dentry->d_fsdata; | ||
101 | fid = v9fs_fid_lookup(dentry); | ||
102 | if (!IS_ERR(fid)) { | ||
103 | spin_lock(&dent->lock); | ||
104 | list_del(&fid->dlist); | ||
105 | spin_unlock(&dent->lock); | ||
130 | } | 106 | } |
131 | 107 | ||
132 | if(down_interruptible(&return_fid->lock)) | 108 | return fid; |
133 | return ERR_PTR(-EINTR); | ||
134 | |||
135 | return return_fid; | ||
136 | } | 109 | } |
137 | 110 | ||
111 | |||
138 | /** | 112 | /** |
139 | * v9fs_fid_clone - lookup the fid for a dentry, clone a private copy and | 113 | * v9fs_fid_clone - lookup the fid for a dentry, clone a private copy and |
140 | * release it | 114 | * release it |
141 | * @dentry: dentry to look for fid in | 115 | * @dentry: dentry to look for fid in |
142 | * | 116 | * |
143 | * find a fid in the dentry and then clone to a new private fid | 117 | * find a fid in the dentry and then clone to a new private fid |
@@ -146,49 +120,15 @@ struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry) | |||
146 | * | 120 | * |
147 | */ | 121 | */ |
148 | 122 | ||
149 | struct v9fs_fid *v9fs_fid_clone(struct dentry *dentry) | 123 | struct p9_fid *v9fs_fid_clone(struct dentry *dentry) |
150 | { | 124 | { |
151 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 125 | struct p9_fid *ofid, *fid; |
152 | struct v9fs_fid *base_fid, *new_fid = ERR_PTR(-EBADF); | ||
153 | struct v9fs_fcall *fcall = NULL; | ||
154 | int fid, err; | ||
155 | |||
156 | base_fid = v9fs_fid_lookup(dentry); | ||
157 | |||
158 | if(IS_ERR(base_fid)) | ||
159 | return base_fid; | ||
160 | |||
161 | if(base_fid) { /* clone fid */ | ||
162 | fid = v9fs_get_idpool(&v9ses->fidpool); | ||
163 | if (fid < 0) { | ||
164 | eprintk(KERN_WARNING, "newfid fails!\n"); | ||
165 | new_fid = ERR_PTR(-ENOSPC); | ||
166 | goto Release_Fid; | ||
167 | } | ||
168 | |||
169 | err = v9fs_t_walk(v9ses, base_fid->fid, fid, NULL, &fcall); | ||
170 | if (err < 0) { | ||
171 | dprintk(DEBUG_ERROR, "clone walk didn't work\n"); | ||
172 | v9fs_put_idpool(fid, &v9ses->fidpool); | ||
173 | new_fid = ERR_PTR(err); | ||
174 | goto Free_Fcall; | ||
175 | } | ||
176 | new_fid = v9fs_fid_create(v9ses, fid); | ||
177 | if (new_fid == NULL) { | ||
178 | dprintk(DEBUG_ERROR, "out of memory\n"); | ||
179 | new_fid = ERR_PTR(-ENOMEM); | ||
180 | } | ||
181 | Free_Fcall: | ||
182 | kfree(fcall); | ||
183 | } | ||
184 | 126 | ||
185 | Release_Fid: | 127 | P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); |
186 | up(&base_fid->lock); | 128 | ofid = v9fs_fid_lookup(dentry); |
187 | return new_fid; | 129 | if (IS_ERR(ofid)) |
188 | } | 130 | return ofid; |
189 | 131 | ||
190 | void v9fs_fid_clunk(struct v9fs_session_info *v9ses, struct v9fs_fid *fid) | 132 | fid = p9_client_walk(ofid, 0, NULL, 1); |
191 | { | 133 | return fid; |
192 | v9fs_t_clunk(v9ses, fid->fid); | ||
193 | v9fs_fid_destroy(fid); | ||
194 | } | 134 | } |
diff --git a/fs/9p/fid.h b/fs/9p/fid.h index 48fc170c26c8..47a0ba742872 100644 --- a/fs/9p/fid.h +++ b/fs/9p/fid.h | |||
@@ -22,41 +22,12 @@ | |||
22 | 22 | ||
23 | #include <linux/list.h> | 23 | #include <linux/list.h> |
24 | 24 | ||
25 | #define FID_OP 0 | 25 | struct v9fs_dentry { |
26 | #define FID_WALK 1 | 26 | spinlock_t lock; /* protect fidlist */ |
27 | #define FID_CREATE 2 | 27 | struct list_head fidlist; |
28 | |||
29 | struct v9fs_fid { | ||
30 | struct list_head list; /* list of fids associated with a dentry */ | ||
31 | struct list_head active; /* XXX - debug */ | ||
32 | |||
33 | struct semaphore lock; | ||
34 | |||
35 | u32 fid; | ||
36 | unsigned char fidopen; /* set when fid is opened */ | ||
37 | unsigned char fidclunked; /* set when fid has already been clunked */ | ||
38 | |||
39 | struct v9fs_qid qid; | ||
40 | u32 iounit; | ||
41 | |||
42 | /* readdir stuff */ | ||
43 | int rdir_fpos; | ||
44 | loff_t rdir_pos; | ||
45 | struct v9fs_fcall *rdir_fcall; | ||
46 | |||
47 | /* management stuff */ | ||
48 | uid_t uid; /* user associated with this fid */ | ||
49 | |||
50 | /* private data */ | ||
51 | struct file *filp; /* backpointer to File struct for open files */ | ||
52 | struct v9fs_session_info *v9ses; /* session info for this FID */ | ||
53 | }; | 28 | }; |
54 | 29 | ||
55 | struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry); | 30 | struct p9_fid *v9fs_fid_lookup(struct dentry *dentry); |
56 | struct v9fs_fid *v9fs_fid_get_created(struct dentry *); | 31 | struct p9_fid *v9fs_fid_lookup_remove(struct dentry *dentry); |
57 | void v9fs_fid_destroy(struct v9fs_fid *fid); | 32 | struct p9_fid *v9fs_fid_clone(struct dentry *dentry); |
58 | struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *, int fid); | 33 | int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid); |
59 | int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry); | ||
60 | struct v9fs_fid *v9fs_fid_clone(struct dentry *dentry); | ||
61 | void v9fs_fid_clunk(struct v9fs_session_info *v9ses, struct v9fs_fid *fid); | ||
62 | |||
diff --git a/fs/9p/mux.c b/fs/9p/mux.c deleted file mode 100644 index c783874a9caf..000000000000 --- a/fs/9p/mux.c +++ /dev/null | |||
@@ -1,1033 +0,0 @@ | |||
1 | /* | ||
2 | * linux/fs/9p/mux.c | ||
3 | * | ||
4 | * Protocol Multiplexer | ||
5 | * | ||
6 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | ||
7 | * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> | ||
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/poll.h> | ||
30 | #include <linux/kthread.h> | ||
31 | #include <linux/idr.h> | ||
32 | #include <linux/mutex.h> | ||
33 | |||
34 | #include "debug.h" | ||
35 | #include "v9fs.h" | ||
36 | #include "9p.h" | ||
37 | #include "conv.h" | ||
38 | #include "transport.h" | ||
39 | #include "mux.h" | ||
40 | |||
41 | #define ERREQFLUSH 1 | ||
42 | #define SCHED_TIMEOUT 10 | ||
43 | #define MAXPOLLWADDR 2 | ||
44 | |||
45 | enum { | ||
46 | Rworksched = 1, /* read work scheduled or running */ | ||
47 | Rpending = 2, /* can read */ | ||
48 | Wworksched = 4, /* write work scheduled or running */ | ||
49 | Wpending = 8, /* can write */ | ||
50 | }; | ||
51 | |||
52 | enum { | ||
53 | None, | ||
54 | Flushing, | ||
55 | Flushed, | ||
56 | }; | ||
57 | |||
58 | struct v9fs_mux_poll_task; | ||
59 | |||
60 | struct v9fs_req { | ||
61 | spinlock_t lock; | ||
62 | int tag; | ||
63 | struct v9fs_fcall *tcall; | ||
64 | struct v9fs_fcall *rcall; | ||
65 | int err; | ||
66 | v9fs_mux_req_callback cb; | ||
67 | void *cba; | ||
68 | int flush; | ||
69 | struct list_head req_list; | ||
70 | }; | ||
71 | |||
72 | struct v9fs_mux_data { | ||
73 | spinlock_t lock; | ||
74 | struct list_head mux_list; | ||
75 | struct v9fs_mux_poll_task *poll_task; | ||
76 | int msize; | ||
77 | unsigned char *extended; | ||
78 | struct v9fs_transport *trans; | ||
79 | struct v9fs_idpool tagpool; | ||
80 | int err; | ||
81 | wait_queue_head_t equeue; | ||
82 | struct list_head req_list; | ||
83 | struct list_head unsent_req_list; | ||
84 | struct v9fs_fcall *rcall; | ||
85 | int rpos; | ||
86 | char *rbuf; | ||
87 | int wpos; | ||
88 | int wsize; | ||
89 | char *wbuf; | ||
90 | wait_queue_t poll_wait[MAXPOLLWADDR]; | ||
91 | wait_queue_head_t *poll_waddr[MAXPOLLWADDR]; | ||
92 | poll_table pt; | ||
93 | struct work_struct rq; | ||
94 | struct work_struct wq; | ||
95 | unsigned long wsched; | ||
96 | }; | ||
97 | |||
98 | struct v9fs_mux_poll_task { | ||
99 | struct task_struct *task; | ||
100 | struct list_head mux_list; | ||
101 | int muxnum; | ||
102 | }; | ||
103 | |||
104 | struct v9fs_mux_rpc { | ||
105 | struct v9fs_mux_data *m; | ||
106 | int err; | ||
107 | struct v9fs_fcall *tcall; | ||
108 | struct v9fs_fcall *rcall; | ||
109 | wait_queue_head_t wqueue; | ||
110 | }; | ||
111 | |||
112 | static int v9fs_poll_proc(void *); | ||
113 | static void v9fs_read_work(struct work_struct *work); | ||
114 | static void v9fs_write_work(struct work_struct *work); | ||
115 | static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address, | ||
116 | poll_table * p); | ||
117 | static u16 v9fs_mux_get_tag(struct v9fs_mux_data *); | ||
118 | static void v9fs_mux_put_tag(struct v9fs_mux_data *, u16); | ||
119 | |||
120 | static DEFINE_MUTEX(v9fs_mux_task_lock); | ||
121 | static struct workqueue_struct *v9fs_mux_wq; | ||
122 | |||
123 | static int v9fs_mux_num; | ||
124 | static int v9fs_mux_poll_task_num; | ||
125 | static struct v9fs_mux_poll_task v9fs_mux_poll_tasks[100]; | ||
126 | |||
127 | int v9fs_mux_global_init(void) | ||
128 | { | ||
129 | int i; | ||
130 | |||
131 | for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) | ||
132 | v9fs_mux_poll_tasks[i].task = NULL; | ||
133 | |||
134 | v9fs_mux_wq = create_workqueue("v9fs"); | ||
135 | if (!v9fs_mux_wq) { | ||
136 | printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n"); | ||
137 | return -ENOMEM; | ||
138 | } | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | void v9fs_mux_global_exit(void) | ||
144 | { | ||
145 | destroy_workqueue(v9fs_mux_wq); | ||
146 | } | ||
147 | |||
148 | /** | ||
149 | * v9fs_mux_calc_poll_procs - calculates the number of polling procs | ||
150 | * based on the number of mounted v9fs filesystems. | ||
151 | * | ||
152 | * The current implementation returns sqrt of the number of mounts. | ||
153 | */ | ||
154 | static int v9fs_mux_calc_poll_procs(int muxnum) | ||
155 | { | ||
156 | int n; | ||
157 | |||
158 | if (v9fs_mux_poll_task_num) | ||
159 | n = muxnum / v9fs_mux_poll_task_num + | ||
160 | (muxnum % v9fs_mux_poll_task_num ? 1 : 0); | ||
161 | else | ||
162 | n = 1; | ||
163 | |||
164 | if (n > ARRAY_SIZE(v9fs_mux_poll_tasks)) | ||
165 | n = ARRAY_SIZE(v9fs_mux_poll_tasks); | ||
166 | |||
167 | return n; | ||
168 | } | ||
169 | |||
170 | static int v9fs_mux_poll_start(struct v9fs_mux_data *m) | ||
171 | { | ||
172 | int i, n; | ||
173 | struct v9fs_mux_poll_task *vpt, *vptlast; | ||
174 | struct task_struct *pproc; | ||
175 | |||
176 | dprintk(DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, v9fs_mux_num, | ||
177 | v9fs_mux_poll_task_num); | ||
178 | mutex_lock(&v9fs_mux_task_lock); | ||
179 | |||
180 | n = v9fs_mux_calc_poll_procs(v9fs_mux_num + 1); | ||
181 | if (n > v9fs_mux_poll_task_num) { | ||
182 | for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) { | ||
183 | if (v9fs_mux_poll_tasks[i].task == NULL) { | ||
184 | vpt = &v9fs_mux_poll_tasks[i]; | ||
185 | dprintk(DEBUG_MUX, "create proc %p\n", vpt); | ||
186 | pproc = kthread_create(v9fs_poll_proc, vpt, | ||
187 | "v9fs-poll"); | ||
188 | |||
189 | if (!IS_ERR(pproc)) { | ||
190 | vpt->task = pproc; | ||
191 | INIT_LIST_HEAD(&vpt->mux_list); | ||
192 | vpt->muxnum = 0; | ||
193 | v9fs_mux_poll_task_num++; | ||
194 | wake_up_process(vpt->task); | ||
195 | } | ||
196 | break; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks)) | ||
201 | dprintk(DEBUG_ERROR, "warning: no free poll slots\n"); | ||
202 | } | ||
203 | |||
204 | n = (v9fs_mux_num + 1) / v9fs_mux_poll_task_num + | ||
205 | ((v9fs_mux_num + 1) % v9fs_mux_poll_task_num ? 1 : 0); | ||
206 | |||
207 | vptlast = NULL; | ||
208 | for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) { | ||
209 | vpt = &v9fs_mux_poll_tasks[i]; | ||
210 | if (vpt->task != NULL) { | ||
211 | vptlast = vpt; | ||
212 | if (vpt->muxnum < n) { | ||
213 | dprintk(DEBUG_MUX, "put in proc %d\n", i); | ||
214 | list_add(&m->mux_list, &vpt->mux_list); | ||
215 | vpt->muxnum++; | ||
216 | m->poll_task = vpt; | ||
217 | memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); | ||
218 | init_poll_funcptr(&m->pt, v9fs_pollwait); | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
224 | if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks)) { | ||
225 | if (vptlast == NULL) | ||
226 | return -ENOMEM; | ||
227 | |||
228 | dprintk(DEBUG_MUX, "put in proc %d\n", i); | ||
229 | list_add(&m->mux_list, &vptlast->mux_list); | ||
230 | vptlast->muxnum++; | ||
231 | m->poll_task = vptlast; | ||
232 | memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); | ||
233 | init_poll_funcptr(&m->pt, v9fs_pollwait); | ||
234 | } | ||
235 | |||
236 | v9fs_mux_num++; | ||
237 | mutex_unlock(&v9fs_mux_task_lock); | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static void v9fs_mux_poll_stop(struct v9fs_mux_data *m) | ||
243 | { | ||
244 | int i; | ||
245 | struct v9fs_mux_poll_task *vpt; | ||
246 | |||
247 | mutex_lock(&v9fs_mux_task_lock); | ||
248 | vpt = m->poll_task; | ||
249 | list_del(&m->mux_list); | ||
250 | for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { | ||
251 | if (m->poll_waddr[i] != NULL) { | ||
252 | remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]); | ||
253 | m->poll_waddr[i] = NULL; | ||
254 | } | ||
255 | } | ||
256 | vpt->muxnum--; | ||
257 | if (!vpt->muxnum) { | ||
258 | dprintk(DEBUG_MUX, "destroy proc %p\n", vpt); | ||
259 | kthread_stop(vpt->task); | ||
260 | vpt->task = NULL; | ||
261 | v9fs_mux_poll_task_num--; | ||
262 | } | ||
263 | v9fs_mux_num--; | ||
264 | mutex_unlock(&v9fs_mux_task_lock); | ||
265 | } | ||
266 | |||
267 | /** | ||
268 | * v9fs_mux_init - allocate and initialize the per-session mux data | ||
269 | * Creates the polling task if this is the first session. | ||
270 | * | ||
271 | * @trans - transport structure | ||
272 | * @msize - maximum message size | ||
273 | * @extended - pointer to the extended flag | ||
274 | */ | ||
275 | struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, | ||
276 | unsigned char *extended) | ||
277 | { | ||
278 | int i, n; | ||
279 | struct v9fs_mux_data *m, *mtmp; | ||
280 | |||
281 | dprintk(DEBUG_MUX, "transport %p msize %d\n", trans, msize); | ||
282 | m = kmalloc(sizeof(struct v9fs_mux_data), GFP_KERNEL); | ||
283 | if (!m) | ||
284 | return ERR_PTR(-ENOMEM); | ||
285 | |||
286 | spin_lock_init(&m->lock); | ||
287 | INIT_LIST_HEAD(&m->mux_list); | ||
288 | m->msize = msize; | ||
289 | m->extended = extended; | ||
290 | m->trans = trans; | ||
291 | idr_init(&m->tagpool.pool); | ||
292 | init_MUTEX(&m->tagpool.lock); | ||
293 | m->err = 0; | ||
294 | init_waitqueue_head(&m->equeue); | ||
295 | INIT_LIST_HEAD(&m->req_list); | ||
296 | INIT_LIST_HEAD(&m->unsent_req_list); | ||
297 | m->rcall = NULL; | ||
298 | m->rpos = 0; | ||
299 | m->rbuf = NULL; | ||
300 | m->wpos = m->wsize = 0; | ||
301 | m->wbuf = NULL; | ||
302 | INIT_WORK(&m->rq, v9fs_read_work); | ||
303 | INIT_WORK(&m->wq, v9fs_write_work); | ||
304 | m->wsched = 0; | ||
305 | memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); | ||
306 | m->poll_task = NULL; | ||
307 | n = v9fs_mux_poll_start(m); | ||
308 | if (n) | ||
309 | return ERR_PTR(n); | ||
310 | |||
311 | n = trans->poll(trans, &m->pt); | ||
312 | if (n & POLLIN) { | ||
313 | dprintk(DEBUG_MUX, "mux %p can read\n", m); | ||
314 | set_bit(Rpending, &m->wsched); | ||
315 | } | ||
316 | |||
317 | if (n & POLLOUT) { | ||
318 | dprintk(DEBUG_MUX, "mux %p can write\n", m); | ||
319 | set_bit(Wpending, &m->wsched); | ||
320 | } | ||
321 | |||
322 | for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { | ||
323 | if (IS_ERR(m->poll_waddr[i])) { | ||
324 | v9fs_mux_poll_stop(m); | ||
325 | mtmp = (void *)m->poll_waddr; /* the error code */ | ||
326 | kfree(m); | ||
327 | m = mtmp; | ||
328 | break; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | return m; | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * v9fs_mux_destroy - cancels all pending requests and frees mux resources | ||
337 | */ | ||
338 | void v9fs_mux_destroy(struct v9fs_mux_data *m) | ||
339 | { | ||
340 | dprintk(DEBUG_MUX, "mux %p prev %p next %p\n", m, | ||
341 | m->mux_list.prev, m->mux_list.next); | ||
342 | v9fs_mux_cancel(m, -ECONNRESET); | ||
343 | |||
344 | if (!list_empty(&m->req_list)) { | ||
345 | /* wait until all processes waiting on this session exit */ | ||
346 | dprintk(DEBUG_MUX, "mux %p waiting for empty request queue\n", | ||
347 | m); | ||
348 | wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000); | ||
349 | dprintk(DEBUG_MUX, "mux %p request queue empty: %d\n", m, | ||
350 | list_empty(&m->req_list)); | ||
351 | } | ||
352 | |||
353 | v9fs_mux_poll_stop(m); | ||
354 | m->trans = NULL; | ||
355 | |||
356 | kfree(m); | ||
357 | } | ||
358 | |||
359 | /** | ||
360 | * v9fs_pollwait - called by files poll operation to add v9fs-poll task | ||
361 | * to files wait queue | ||
362 | */ | ||
363 | static void | ||
364 | v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address, | ||
365 | poll_table * p) | ||
366 | { | ||
367 | int i; | ||
368 | struct v9fs_mux_data *m; | ||
369 | |||
370 | m = container_of(p, struct v9fs_mux_data, pt); | ||
371 | for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) | ||
372 | if (m->poll_waddr[i] == NULL) | ||
373 | break; | ||
374 | |||
375 | if (i >= ARRAY_SIZE(m->poll_waddr)) { | ||
376 | dprintk(DEBUG_ERROR, "not enough wait_address slots\n"); | ||
377 | return; | ||
378 | } | ||
379 | |||
380 | m->poll_waddr[i] = wait_address; | ||
381 | |||
382 | if (!wait_address) { | ||
383 | dprintk(DEBUG_ERROR, "no wait_address\n"); | ||
384 | m->poll_waddr[i] = ERR_PTR(-EIO); | ||
385 | return; | ||
386 | } | ||
387 | |||
388 | init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task); | ||
389 | add_wait_queue(wait_address, &m->poll_wait[i]); | ||
390 | } | ||
391 | |||
392 | /** | ||
393 | * v9fs_poll_mux - polls a mux and schedules read or write works if necessary | ||
394 | */ | ||
395 | static void v9fs_poll_mux(struct v9fs_mux_data *m) | ||
396 | { | ||
397 | int n; | ||
398 | |||
399 | if (m->err < 0) | ||
400 | return; | ||
401 | |||
402 | n = m->trans->poll(m->trans, NULL); | ||
403 | if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { | ||
404 | dprintk(DEBUG_MUX, "error mux %p err %d\n", m, n); | ||
405 | if (n >= 0) | ||
406 | n = -ECONNRESET; | ||
407 | v9fs_mux_cancel(m, n); | ||
408 | } | ||
409 | |||
410 | if (n & POLLIN) { | ||
411 | set_bit(Rpending, &m->wsched); | ||
412 | dprintk(DEBUG_MUX, "mux %p can read\n", m); | ||
413 | if (!test_and_set_bit(Rworksched, &m->wsched)) { | ||
414 | dprintk(DEBUG_MUX, "schedule read work mux %p\n", m); | ||
415 | queue_work(v9fs_mux_wq, &m->rq); | ||
416 | } | ||
417 | } | ||
418 | |||
419 | if (n & POLLOUT) { | ||
420 | set_bit(Wpending, &m->wsched); | ||
421 | dprintk(DEBUG_MUX, "mux %p can write\n", m); | ||
422 | if ((m->wsize || !list_empty(&m->unsent_req_list)) | ||
423 | && !test_and_set_bit(Wworksched, &m->wsched)) { | ||
424 | dprintk(DEBUG_MUX, "schedule write work mux %p\n", m); | ||
425 | queue_work(v9fs_mux_wq, &m->wq); | ||
426 | } | ||
427 | } | ||
428 | } | ||
429 | |||
430 | /** | ||
431 | * v9fs_poll_proc - polls all v9fs transports for new events and queues | ||
432 | * the appropriate work to the work queue | ||
433 | */ | ||
434 | static int v9fs_poll_proc(void *a) | ||
435 | { | ||
436 | struct v9fs_mux_data *m, *mtmp; | ||
437 | struct v9fs_mux_poll_task *vpt; | ||
438 | |||
439 | vpt = a; | ||
440 | dprintk(DEBUG_MUX, "start %p %p\n", current, vpt); | ||
441 | while (!kthread_should_stop()) { | ||
442 | set_current_state(TASK_INTERRUPTIBLE); | ||
443 | |||
444 | list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) { | ||
445 | v9fs_poll_mux(m); | ||
446 | } | ||
447 | |||
448 | dprintk(DEBUG_MUX, "sleeping...\n"); | ||
449 | schedule_timeout(SCHED_TIMEOUT * HZ); | ||
450 | } | ||
451 | |||
452 | __set_current_state(TASK_RUNNING); | ||
453 | dprintk(DEBUG_MUX, "finish\n"); | ||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | /** | ||
458 | * v9fs_write_work - called when a transport can send some data | ||
459 | */ | ||
460 | static void v9fs_write_work(struct work_struct *work) | ||
461 | { | ||
462 | int n, err; | ||
463 | struct v9fs_mux_data *m; | ||
464 | struct v9fs_req *req; | ||
465 | |||
466 | m = container_of(work, struct v9fs_mux_data, wq); | ||
467 | |||
468 | if (m->err < 0) { | ||
469 | clear_bit(Wworksched, &m->wsched); | ||
470 | return; | ||
471 | } | ||
472 | |||
473 | if (!m->wsize) { | ||
474 | if (list_empty(&m->unsent_req_list)) { | ||
475 | clear_bit(Wworksched, &m->wsched); | ||
476 | return; | ||
477 | } | ||
478 | |||
479 | spin_lock(&m->lock); | ||
480 | again: | ||
481 | req = list_entry(m->unsent_req_list.next, struct v9fs_req, | ||
482 | req_list); | ||
483 | list_move_tail(&req->req_list, &m->req_list); | ||
484 | if (req->err == ERREQFLUSH) | ||
485 | goto again; | ||
486 | |||
487 | m->wbuf = req->tcall->sdata; | ||
488 | m->wsize = req->tcall->size; | ||
489 | m->wpos = 0; | ||
490 | dump_data(m->wbuf, m->wsize); | ||
491 | spin_unlock(&m->lock); | ||
492 | } | ||
493 | |||
494 | dprintk(DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos, m->wsize); | ||
495 | clear_bit(Wpending, &m->wsched); | ||
496 | err = m->trans->write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos); | ||
497 | dprintk(DEBUG_MUX, "mux %p sent %d bytes\n", m, err); | ||
498 | if (err == -EAGAIN) { | ||
499 | clear_bit(Wworksched, &m->wsched); | ||
500 | return; | ||
501 | } | ||
502 | |||
503 | if (err <= 0) | ||
504 | goto error; | ||
505 | |||
506 | m->wpos += err; | ||
507 | if (m->wpos == m->wsize) | ||
508 | m->wpos = m->wsize = 0; | ||
509 | |||
510 | if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) { | ||
511 | if (test_and_clear_bit(Wpending, &m->wsched)) | ||
512 | n = POLLOUT; | ||
513 | else | ||
514 | n = m->trans->poll(m->trans, NULL); | ||
515 | |||
516 | if (n & POLLOUT) { | ||
517 | dprintk(DEBUG_MUX, "schedule write work mux %p\n", m); | ||
518 | queue_work(v9fs_mux_wq, &m->wq); | ||
519 | } else | ||
520 | clear_bit(Wworksched, &m->wsched); | ||
521 | } else | ||
522 | clear_bit(Wworksched, &m->wsched); | ||
523 | |||
524 | return; | ||
525 | |||
526 | error: | ||
527 | v9fs_mux_cancel(m, err); | ||
528 | clear_bit(Wworksched, &m->wsched); | ||
529 | } | ||
530 | |||
531 | static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) | ||
532 | { | ||
533 | int ecode; | ||
534 | struct v9fs_str *ename; | ||
535 | |||
536 | if (!req->err && req->rcall->id == RERROR) { | ||
537 | ecode = req->rcall->params.rerror.errno; | ||
538 | ename = &req->rcall->params.rerror.error; | ||
539 | |||
540 | dprintk(DEBUG_MUX, "Rerror %.*s\n", ename->len, ename->str); | ||
541 | |||
542 | if (*m->extended) | ||
543 | req->err = -ecode; | ||
544 | |||
545 | if (!req->err) { | ||
546 | req->err = v9fs_errstr2errno(ename->str, ename->len); | ||
547 | |||
548 | if (!req->err) { /* string match failed */ | ||
549 | PRINT_FCALL_ERROR("unknown error", req->rcall); | ||
550 | } | ||
551 | |||
552 | if (!req->err) | ||
553 | req->err = -ESERVERFAULT; | ||
554 | } | ||
555 | } else if (req->tcall && req->rcall->id != req->tcall->id + 1) { | ||
556 | dprintk(DEBUG_ERROR, "fcall mismatch: expected %d, got %d\n", | ||
557 | req->tcall->id + 1, req->rcall->id); | ||
558 | if (!req->err) | ||
559 | req->err = -EIO; | ||
560 | } | ||
561 | } | ||
562 | |||
563 | /** | ||
564 | * v9fs_read_work - called when there is some data to be read from a transport | ||
565 | */ | ||
566 | static void v9fs_read_work(struct work_struct *work) | ||
567 | { | ||
568 | int n, err; | ||
569 | struct v9fs_mux_data *m; | ||
570 | struct v9fs_req *req, *rptr, *rreq; | ||
571 | struct v9fs_fcall *rcall; | ||
572 | char *rbuf; | ||
573 | |||
574 | m = container_of(work, struct v9fs_mux_data, rq); | ||
575 | |||
576 | if (m->err < 0) | ||
577 | return; | ||
578 | |||
579 | rcall = NULL; | ||
580 | dprintk(DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); | ||
581 | |||
582 | if (!m->rcall) { | ||
583 | m->rcall = | ||
584 | kmalloc(sizeof(struct v9fs_fcall) + m->msize, GFP_KERNEL); | ||
585 | if (!m->rcall) { | ||
586 | err = -ENOMEM; | ||
587 | goto error; | ||
588 | } | ||
589 | |||
590 | m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall); | ||
591 | m->rpos = 0; | ||
592 | } | ||
593 | |||
594 | clear_bit(Rpending, &m->wsched); | ||
595 | err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos); | ||
596 | dprintk(DEBUG_MUX, "mux %p got %d bytes\n", m, err); | ||
597 | if (err == -EAGAIN) { | ||
598 | clear_bit(Rworksched, &m->wsched); | ||
599 | return; | ||
600 | } | ||
601 | |||
602 | if (err <= 0) | ||
603 | goto error; | ||
604 | |||
605 | m->rpos += err; | ||
606 | while (m->rpos > 4) { | ||
607 | n = le32_to_cpu(*(__le32 *) m->rbuf); | ||
608 | if (n >= m->msize) { | ||
609 | dprintk(DEBUG_ERROR, | ||
610 | "requested packet size too big: %d\n", n); | ||
611 | err = -EIO; | ||
612 | goto error; | ||
613 | } | ||
614 | |||
615 | if (m->rpos < n) | ||
616 | break; | ||
617 | |||
618 | dump_data(m->rbuf, n); | ||
619 | err = | ||
620 | v9fs_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended); | ||
621 | if (err < 0) { | ||
622 | goto error; | ||
623 | } | ||
624 | |||
625 | if ((v9fs_debug_level&DEBUG_FCALL) == DEBUG_FCALL) { | ||
626 | char buf[150]; | ||
627 | |||
628 | v9fs_printfcall(buf, sizeof(buf), m->rcall, | ||
629 | *m->extended); | ||
630 | printk(KERN_NOTICE ">>> %p %s\n", m, buf); | ||
631 | } | ||
632 | |||
633 | rcall = m->rcall; | ||
634 | rbuf = m->rbuf; | ||
635 | if (m->rpos > n) { | ||
636 | m->rcall = kmalloc(sizeof(struct v9fs_fcall) + m->msize, | ||
637 | GFP_KERNEL); | ||
638 | if (!m->rcall) { | ||
639 | err = -ENOMEM; | ||
640 | goto error; | ||
641 | } | ||
642 | |||
643 | m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall); | ||
644 | memmove(m->rbuf, rbuf + n, m->rpos - n); | ||
645 | m->rpos -= n; | ||
646 | } else { | ||
647 | m->rcall = NULL; | ||
648 | m->rbuf = NULL; | ||
649 | m->rpos = 0; | ||
650 | } | ||
651 | |||
652 | dprintk(DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, rcall->id, | ||
653 | rcall->tag); | ||
654 | |||
655 | req = NULL; | ||
656 | spin_lock(&m->lock); | ||
657 | list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { | ||
658 | if (rreq->tag == rcall->tag) { | ||
659 | req = rreq; | ||
660 | if (req->flush != Flushing) | ||
661 | list_del(&req->req_list); | ||
662 | break; | ||
663 | } | ||
664 | } | ||
665 | spin_unlock(&m->lock); | ||
666 | |||
667 | if (req) { | ||
668 | req->rcall = rcall; | ||
669 | process_request(m, req); | ||
670 | |||
671 | if (req->flush != Flushing) { | ||
672 | if (req->cb) | ||
673 | (*req->cb) (req, req->cba); | ||
674 | else | ||
675 | kfree(req->rcall); | ||
676 | |||
677 | wake_up(&m->equeue); | ||
678 | } | ||
679 | } else { | ||
680 | if (err >= 0 && rcall->id != RFLUSH) | ||
681 | dprintk(DEBUG_ERROR, | ||
682 | "unexpected response mux %p id %d tag %d\n", | ||
683 | m, rcall->id, rcall->tag); | ||
684 | kfree(rcall); | ||
685 | } | ||
686 | } | ||
687 | |||
688 | if (!list_empty(&m->req_list)) { | ||
689 | if (test_and_clear_bit(Rpending, &m->wsched)) | ||
690 | n = POLLIN; | ||
691 | else | ||
692 | n = m->trans->poll(m->trans, NULL); | ||
693 | |||
694 | if (n & POLLIN) { | ||
695 | dprintk(DEBUG_MUX, "schedule read work mux %p\n", m); | ||
696 | queue_work(v9fs_mux_wq, &m->rq); | ||
697 | } else | ||
698 | clear_bit(Rworksched, &m->wsched); | ||
699 | } else | ||
700 | clear_bit(Rworksched, &m->wsched); | ||
701 | |||
702 | return; | ||
703 | |||
704 | error: | ||
705 | v9fs_mux_cancel(m, err); | ||
706 | clear_bit(Rworksched, &m->wsched); | ||
707 | } | ||
708 | |||
709 | /** | ||
710 | * v9fs_send_request - send 9P request | ||
711 | * The function can sleep until the request is scheduled for sending. | ||
712 | * The function can be interrupted. Return from the function is not | ||
713 | * a guarantee that the request is sent successfully. Can return errors | ||
714 | * that can be retrieved by PTR_ERR macros. | ||
715 | * | ||
716 | * @m: mux data | ||
717 | * @tc: request to be sent | ||
718 | * @cb: callback function to call when response is received | ||
719 | * @cba: parameter to pass to the callback function | ||
720 | */ | ||
721 | static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m, | ||
722 | struct v9fs_fcall *tc, | ||
723 | v9fs_mux_req_callback cb, void *cba) | ||
724 | { | ||
725 | int n; | ||
726 | struct v9fs_req *req; | ||
727 | |||
728 | dprintk(DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current, | ||
729 | tc, tc->id); | ||
730 | if (m->err < 0) | ||
731 | return ERR_PTR(m->err); | ||
732 | |||
733 | req = kmalloc(sizeof(struct v9fs_req), GFP_KERNEL); | ||
734 | if (!req) | ||
735 | return ERR_PTR(-ENOMEM); | ||
736 | |||
737 | if (tc->id == TVERSION) | ||
738 | n = V9FS_NOTAG; | ||
739 | else | ||
740 | n = v9fs_mux_get_tag(m); | ||
741 | |||
742 | if (n < 0) | ||
743 | return ERR_PTR(-ENOMEM); | ||
744 | |||
745 | v9fs_set_tag(tc, n); | ||
746 | if ((v9fs_debug_level&DEBUG_FCALL) == DEBUG_FCALL) { | ||
747 | char buf[150]; | ||
748 | |||
749 | v9fs_printfcall(buf, sizeof(buf), tc, *m->extended); | ||
750 | printk(KERN_NOTICE "<<< %p %s\n", m, buf); | ||
751 | } | ||
752 | |||
753 | spin_lock_init(&req->lock); | ||
754 | req->tag = n; | ||
755 | req->tcall = tc; | ||
756 | req->rcall = NULL; | ||
757 | req->err = 0; | ||
758 | req->cb = cb; | ||
759 | req->cba = cba; | ||
760 | req->flush = None; | ||
761 | |||
762 | spin_lock(&m->lock); | ||
763 | list_add_tail(&req->req_list, &m->unsent_req_list); | ||
764 | spin_unlock(&m->lock); | ||
765 | |||
766 | if (test_and_clear_bit(Wpending, &m->wsched)) | ||
767 | n = POLLOUT; | ||
768 | else | ||
769 | n = m->trans->poll(m->trans, NULL); | ||
770 | |||
771 | if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched)) | ||
772 | queue_work(v9fs_mux_wq, &m->wq); | ||
773 | |||
774 | return req; | ||
775 | } | ||
776 | |||
777 | static void v9fs_mux_free_request(struct v9fs_mux_data *m, struct v9fs_req *req) | ||
778 | { | ||
779 | v9fs_mux_put_tag(m, req->tag); | ||
780 | kfree(req); | ||
781 | } | ||
782 | |||
783 | static void v9fs_mux_flush_cb(struct v9fs_req *freq, void *a) | ||
784 | { | ||
785 | v9fs_mux_req_callback cb; | ||
786 | int tag; | ||
787 | struct v9fs_mux_data *m; | ||
788 | struct v9fs_req *req, *rreq, *rptr; | ||
789 | |||
790 | m = a; | ||
791 | dprintk(DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m, | ||
792 | freq->tcall, freq->rcall, freq->err, | ||
793 | freq->tcall->params.tflush.oldtag); | ||
794 | |||
795 | spin_lock(&m->lock); | ||
796 | cb = NULL; | ||
797 | tag = freq->tcall->params.tflush.oldtag; | ||
798 | req = NULL; | ||
799 | list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { | ||
800 | if (rreq->tag == tag) { | ||
801 | req = rreq; | ||
802 | list_del(&req->req_list); | ||
803 | break; | ||
804 | } | ||
805 | } | ||
806 | spin_unlock(&m->lock); | ||
807 | |||
808 | if (req) { | ||
809 | spin_lock(&req->lock); | ||
810 | req->flush = Flushed; | ||
811 | spin_unlock(&req->lock); | ||
812 | |||
813 | if (req->cb) | ||
814 | (*req->cb) (req, req->cba); | ||
815 | else | ||
816 | kfree(req->rcall); | ||
817 | |||
818 | wake_up(&m->equeue); | ||
819 | } | ||
820 | |||
821 | kfree(freq->tcall); | ||
822 | kfree(freq->rcall); | ||
823 | v9fs_mux_free_request(m, freq); | ||
824 | } | ||
825 | |||
826 | static int | ||
827 | v9fs_mux_flush_request(struct v9fs_mux_data *m, struct v9fs_req *req) | ||
828 | { | ||
829 | struct v9fs_fcall *fc; | ||
830 | struct v9fs_req *rreq, *rptr; | ||
831 | |||
832 | dprintk(DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag); | ||
833 | |||
834 | /* if a response was received for a request, do nothing */ | ||
835 | spin_lock(&req->lock); | ||
836 | if (req->rcall || req->err) { | ||
837 | spin_unlock(&req->lock); | ||
838 | dprintk(DEBUG_MUX, "mux %p req %p response already received\n", m, req); | ||
839 | return 0; | ||
840 | } | ||
841 | |||
842 | req->flush = Flushing; | ||
843 | spin_unlock(&req->lock); | ||
844 | |||
845 | spin_lock(&m->lock); | ||
846 | /* if the request is not sent yet, just remove it from the list */ | ||
847 | list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) { | ||
848 | if (rreq->tag == req->tag) { | ||
849 | dprintk(DEBUG_MUX, "mux %p req %p request is not sent yet\n", m, req); | ||
850 | list_del(&rreq->req_list); | ||
851 | req->flush = Flushed; | ||
852 | spin_unlock(&m->lock); | ||
853 | if (req->cb) | ||
854 | (*req->cb) (req, req->cba); | ||
855 | return 0; | ||
856 | } | ||
857 | } | ||
858 | spin_unlock(&m->lock); | ||
859 | |||
860 | clear_thread_flag(TIF_SIGPENDING); | ||
861 | fc = v9fs_create_tflush(req->tag); | ||
862 | v9fs_send_request(m, fc, v9fs_mux_flush_cb, m); | ||
863 | return 1; | ||
864 | } | ||
865 | |||
866 | static void | ||
867 | v9fs_mux_rpc_cb(struct v9fs_req *req, void *a) | ||
868 | { | ||
869 | struct v9fs_mux_rpc *r; | ||
870 | |||
871 | dprintk(DEBUG_MUX, "req %p r %p\n", req, a); | ||
872 | r = a; | ||
873 | r->rcall = req->rcall; | ||
874 | r->err = req->err; | ||
875 | |||
876 | if (req->flush!=None && !req->err) | ||
877 | r->err = -ERESTARTSYS; | ||
878 | |||
879 | wake_up(&r->wqueue); | ||
880 | } | ||
881 | |||
882 | /** | ||
883 | * v9fs_mux_rpc - sends 9P request and waits until a response is available. | ||
884 | * The function can be interrupted. | ||
885 | * @m: mux data | ||
886 | * @tc: request to be sent | ||
887 | * @rc: pointer where a pointer to the response is stored | ||
888 | */ | ||
889 | int | ||
890 | v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc, | ||
891 | struct v9fs_fcall **rc) | ||
892 | { | ||
893 | int err, sigpending; | ||
894 | unsigned long flags; | ||
895 | struct v9fs_req *req; | ||
896 | struct v9fs_mux_rpc r; | ||
897 | |||
898 | r.err = 0; | ||
899 | r.tcall = tc; | ||
900 | r.rcall = NULL; | ||
901 | r.m = m; | ||
902 | init_waitqueue_head(&r.wqueue); | ||
903 | |||
904 | if (rc) | ||
905 | *rc = NULL; | ||
906 | |||
907 | sigpending = 0; | ||
908 | if (signal_pending(current)) { | ||
909 | sigpending = 1; | ||
910 | clear_thread_flag(TIF_SIGPENDING); | ||
911 | } | ||
912 | |||
913 | req = v9fs_send_request(m, tc, v9fs_mux_rpc_cb, &r); | ||
914 | if (IS_ERR(req)) { | ||
915 | err = PTR_ERR(req); | ||
916 | dprintk(DEBUG_MUX, "error %d\n", err); | ||
917 | return err; | ||
918 | } | ||
919 | |||
920 | err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0); | ||
921 | if (r.err < 0) | ||
922 | err = r.err; | ||
923 | |||
924 | if (err == -ERESTARTSYS && m->trans->status == Connected && m->err == 0) { | ||
925 | if (v9fs_mux_flush_request(m, req)) { | ||
926 | /* wait until we get response of the flush message */ | ||
927 | do { | ||
928 | clear_thread_flag(TIF_SIGPENDING); | ||
929 | err = wait_event_interruptible(r.wqueue, | ||
930 | r.rcall || r.err); | ||
931 | } while (!r.rcall && !r.err && err==-ERESTARTSYS && | ||
932 | m->trans->status==Connected && !m->err); | ||
933 | |||
934 | err = -ERESTARTSYS; | ||
935 | } | ||
936 | sigpending = 1; | ||
937 | } | ||
938 | |||
939 | if (sigpending) { | ||
940 | spin_lock_irqsave(¤t->sighand->siglock, flags); | ||
941 | recalc_sigpending(); | ||
942 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
943 | } | ||
944 | |||
945 | if (rc) | ||
946 | *rc = r.rcall; | ||
947 | else | ||
948 | kfree(r.rcall); | ||
949 | |||
950 | v9fs_mux_free_request(m, req); | ||
951 | if (err > 0) | ||
952 | err = -EIO; | ||
953 | |||
954 | return err; | ||
955 | } | ||
956 | |||
957 | #if 0 | ||
958 | /** | ||
959 | * v9fs_mux_rpcnb - sends 9P request without waiting for response. | ||
960 | * @m: mux data | ||
961 | * @tc: request to be sent | ||
962 | * @cb: callback function to be called when response arrives | ||
963 | * @cba: value to pass to the callback function | ||
964 | */ | ||
965 | int v9fs_mux_rpcnb(struct v9fs_mux_data *m, struct v9fs_fcall *tc, | ||
966 | v9fs_mux_req_callback cb, void *a) | ||
967 | { | ||
968 | int err; | ||
969 | struct v9fs_req *req; | ||
970 | |||
971 | req = v9fs_send_request(m, tc, cb, a); | ||
972 | if (IS_ERR(req)) { | ||
973 | err = PTR_ERR(req); | ||
974 | dprintk(DEBUG_MUX, "error %d\n", err); | ||
975 | return PTR_ERR(req); | ||
976 | } | ||
977 | |||
978 | dprintk(DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag); | ||
979 | return 0; | ||
980 | } | ||
981 | #endif /* 0 */ | ||
982 | |||
983 | /** | ||
984 | * v9fs_mux_cancel - cancel all pending requests with error | ||
985 | * @m: mux data | ||
986 | * @err: error code | ||
987 | */ | ||
988 | void v9fs_mux_cancel(struct v9fs_mux_data *m, int err) | ||
989 | { | ||
990 | struct v9fs_req *req, *rtmp; | ||
991 | LIST_HEAD(cancel_list); | ||
992 | |||
993 | dprintk(DEBUG_ERROR, "mux %p err %d\n", m, err); | ||
994 | m->err = err; | ||
995 | spin_lock(&m->lock); | ||
996 | list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { | ||
997 | list_move(&req->req_list, &cancel_list); | ||
998 | } | ||
999 | list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { | ||
1000 | list_move(&req->req_list, &cancel_list); | ||
1001 | } | ||
1002 | spin_unlock(&m->lock); | ||
1003 | |||
1004 | list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { | ||
1005 | list_del(&req->req_list); | ||
1006 | if (!req->err) | ||
1007 | req->err = err; | ||
1008 | |||
1009 | if (req->cb) | ||
1010 | (*req->cb) (req, req->cba); | ||
1011 | else | ||
1012 | kfree(req->rcall); | ||
1013 | } | ||
1014 | |||
1015 | wake_up(&m->equeue); | ||
1016 | } | ||
1017 | |||
1018 | static u16 v9fs_mux_get_tag(struct v9fs_mux_data *m) | ||
1019 | { | ||
1020 | int tag; | ||
1021 | |||
1022 | tag = v9fs_get_idpool(&m->tagpool); | ||
1023 | if (tag < 0) | ||
1024 | return V9FS_NOTAG; | ||
1025 | else | ||
1026 | return (u16) tag; | ||
1027 | } | ||
1028 | |||
1029 | static void v9fs_mux_put_tag(struct v9fs_mux_data *m, u16 tag) | ||
1030 | { | ||
1031 | if (tag != V9FS_NOTAG && v9fs_check_idpool(tag, &m->tagpool)) | ||
1032 | v9fs_put_idpool(tag, &m->tagpool); | ||
1033 | } | ||
diff --git a/fs/9p/mux.h b/fs/9p/mux.h deleted file mode 100644 index fb10c50186a1..000000000000 --- a/fs/9p/mux.h +++ /dev/null | |||
@@ -1,55 +0,0 @@ | |||
1 | /* | ||
2 | * linux/fs/9p/mux.h | ||
3 | * | ||
4 | * Multiplexer Definitions | ||
5 | * | ||
6 | * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net> | ||
7 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | ||
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 | struct v9fs_mux_data; | ||
27 | struct v9fs_req; | ||
28 | |||
29 | /** | ||
30 | * v9fs_mux_req_callback - callback function that is called when the | ||
31 | * response of a request is received. The callback is called from | ||
32 | * a workqueue and shouldn't block. | ||
33 | * | ||
34 | * @a - the pointer that was specified when the request was send to be | ||
35 | * passed to the callback | ||
36 | * @tc - request call | ||
37 | * @rc - response call | ||
38 | * @err - error code (non-zero if error occured) | ||
39 | */ | ||
40 | typedef void (*v9fs_mux_req_callback)(struct v9fs_req *req, void *a); | ||
41 | |||
42 | int v9fs_mux_global_init(void); | ||
43 | void v9fs_mux_global_exit(void); | ||
44 | |||
45 | struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, | ||
46 | unsigned char *extended); | ||
47 | void v9fs_mux_destroy(struct v9fs_mux_data *); | ||
48 | |||
49 | int v9fs_mux_send(struct v9fs_mux_data *m, struct v9fs_fcall *tc); | ||
50 | struct v9fs_fcall *v9fs_mux_recv(struct v9fs_mux_data *m); | ||
51 | int v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc, struct v9fs_fcall **rc); | ||
52 | |||
53 | void v9fs_mux_flush(struct v9fs_mux_data *m, int sendflush); | ||
54 | void v9fs_mux_cancel(struct v9fs_mux_data *m, int err); | ||
55 | int v9fs_errstr2errno(char *errstr, int len); | ||
diff --git a/fs/9p/trans_fd.c b/fs/9p/trans_fd.c deleted file mode 100644 index 34d43355beb7..000000000000 --- a/fs/9p/trans_fd.c +++ /dev/null | |||
@@ -1,308 +0,0 @@ | |||
1 | /* | ||
2 | * linux/fs/9p/trans_fd.c | ||
3 | * | ||
4 | * Fd transport layer. Includes deprecated socket layer. | ||
5 | * | ||
6 | * Copyright (C) 2006 by Russ Cox <rsc@swtch.com> | ||
7 | * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> | ||
8 | * Copyright (C) 2004-2005 by Eric Van Hensbergen <ericvh@gmail.com> | ||
9 | * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 | ||
13 | * as published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to: | ||
22 | * Free Software Foundation | ||
23 | * 51 Franklin Street, Fifth Floor | ||
24 | * Boston, MA 02111-1301 USA | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <linux/in.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/net.h> | ||
31 | #include <linux/ipv6.h> | ||
32 | #include <linux/errno.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/un.h> | ||
35 | #include <asm/uaccess.h> | ||
36 | #include <linux/inet.h> | ||
37 | #include <linux/idr.h> | ||
38 | #include <linux/file.h> | ||
39 | |||
40 | #include "debug.h" | ||
41 | #include "v9fs.h" | ||
42 | #include "transport.h" | ||
43 | |||
44 | #define V9FS_PORT 564 | ||
45 | |||
46 | struct v9fs_trans_fd { | ||
47 | struct file *rd; | ||
48 | struct file *wr; | ||
49 | }; | ||
50 | |||
51 | /** | ||
52 | * v9fs_fd_read- read from a fd | ||
53 | * @v9ses: session information | ||
54 | * @v: buffer to receive data into | ||
55 | * @len: size of receive buffer | ||
56 | * | ||
57 | */ | ||
58 | static int v9fs_fd_read(struct v9fs_transport *trans, void *v, int len) | ||
59 | { | ||
60 | int ret; | ||
61 | struct v9fs_trans_fd *ts; | ||
62 | |||
63 | if (!trans || trans->status == Disconnected || !(ts = trans->priv)) | ||
64 | return -EREMOTEIO; | ||
65 | |||
66 | if (!(ts->rd->f_flags & O_NONBLOCK)) | ||
67 | dprintk(DEBUG_ERROR, "blocking read ...\n"); | ||
68 | |||
69 | ret = kernel_read(ts->rd, ts->rd->f_pos, v, len); | ||
70 | if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) | ||
71 | trans->status = Disconnected; | ||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | /** | ||
76 | * v9fs_fd_write - write to a socket | ||
77 | * @v9ses: session information | ||
78 | * @v: buffer to send data from | ||
79 | * @len: size of send buffer | ||
80 | * | ||
81 | */ | ||
82 | static int v9fs_fd_write(struct v9fs_transport *trans, void *v, int len) | ||
83 | { | ||
84 | int ret; | ||
85 | mm_segment_t oldfs; | ||
86 | struct v9fs_trans_fd *ts; | ||
87 | |||
88 | if (!trans || trans->status == Disconnected || !(ts = trans->priv)) | ||
89 | return -EREMOTEIO; | ||
90 | |||
91 | if (!(ts->wr->f_flags & O_NONBLOCK)) | ||
92 | dprintk(DEBUG_ERROR, "blocking write ...\n"); | ||
93 | |||
94 | oldfs = get_fs(); | ||
95 | set_fs(get_ds()); | ||
96 | /* The cast to a user pointer is valid due to the set_fs() */ | ||
97 | ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos); | ||
98 | set_fs(oldfs); | ||
99 | |||
100 | if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) | ||
101 | trans->status = Disconnected; | ||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | static unsigned int | ||
106 | v9fs_fd_poll(struct v9fs_transport *trans, struct poll_table_struct *pt) | ||
107 | { | ||
108 | int ret, n; | ||
109 | struct v9fs_trans_fd *ts; | ||
110 | mm_segment_t oldfs; | ||
111 | |||
112 | if (!trans || trans->status != Connected || !(ts = trans->priv)) | ||
113 | return -EREMOTEIO; | ||
114 | |||
115 | if (!ts->rd->f_op || !ts->rd->f_op->poll) | ||
116 | return -EIO; | ||
117 | |||
118 | if (!ts->wr->f_op || !ts->wr->f_op->poll) | ||
119 | return -EIO; | ||
120 | |||
121 | oldfs = get_fs(); | ||
122 | set_fs(get_ds()); | ||
123 | |||
124 | ret = ts->rd->f_op->poll(ts->rd, pt); | ||
125 | if (ret < 0) | ||
126 | goto end; | ||
127 | |||
128 | if (ts->rd != ts->wr) { | ||
129 | n = ts->wr->f_op->poll(ts->wr, pt); | ||
130 | if (n < 0) { | ||
131 | ret = n; | ||
132 | goto end; | ||
133 | } | ||
134 | ret = (ret & ~POLLOUT) | (n & ~POLLIN); | ||
135 | } | ||
136 | |||
137 | end: | ||
138 | set_fs(oldfs); | ||
139 | return ret; | ||
140 | } | ||
141 | |||
142 | static int v9fs_fd_open(struct v9fs_session_info *v9ses, int rfd, int wfd) | ||
143 | { | ||
144 | struct v9fs_transport *trans = v9ses->transport; | ||
145 | struct v9fs_trans_fd *ts = kmalloc(sizeof(struct v9fs_trans_fd), | ||
146 | GFP_KERNEL); | ||
147 | if (!ts) | ||
148 | return -ENOMEM; | ||
149 | |||
150 | ts->rd = fget(rfd); | ||
151 | ts->wr = fget(wfd); | ||
152 | if (!ts->rd || !ts->wr) { | ||
153 | if (ts->rd) | ||
154 | fput(ts->rd); | ||
155 | if (ts->wr) | ||
156 | fput(ts->wr); | ||
157 | kfree(ts); | ||
158 | return -EIO; | ||
159 | } | ||
160 | |||
161 | trans->priv = ts; | ||
162 | trans->status = Connected; | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int v9fs_fd_init(struct v9fs_session_info *v9ses, const char *addr, | ||
168 | char *data) | ||
169 | { | ||
170 | if (v9ses->rfdno == ~0 || v9ses->wfdno == ~0) { | ||
171 | printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n"); | ||
172 | return -ENOPROTOOPT; | ||
173 | } | ||
174 | |||
175 | return v9fs_fd_open(v9ses, v9ses->rfdno, v9ses->wfdno); | ||
176 | } | ||
177 | |||
178 | static int v9fs_socket_open(struct v9fs_session_info *v9ses, | ||
179 | struct socket *csocket) | ||
180 | { | ||
181 | int fd, ret; | ||
182 | |||
183 | csocket->sk->sk_allocation = GFP_NOIO; | ||
184 | if ((fd = sock_map_fd(csocket)) < 0) { | ||
185 | eprintk(KERN_ERR, "v9fs_socket_open: failed to map fd\n"); | ||
186 | ret = fd; | ||
187 | release_csocket: | ||
188 | sock_release(csocket); | ||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | if ((ret = v9fs_fd_open(v9ses, fd, fd)) < 0) { | ||
193 | sockfd_put(csocket); | ||
194 | eprintk(KERN_ERR, "v9fs_socket_open: failed to open fd\n"); | ||
195 | goto release_csocket; | ||
196 | } | ||
197 | |||
198 | ((struct v9fs_trans_fd *)v9ses->transport->priv)->rd->f_flags |= | ||
199 | O_NONBLOCK; | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static int v9fs_tcp_init(struct v9fs_session_info *v9ses, const char *addr, | ||
204 | char *data) | ||
205 | { | ||
206 | int ret; | ||
207 | struct socket *csocket = NULL; | ||
208 | struct sockaddr_in sin_server; | ||
209 | |||
210 | sin_server.sin_family = AF_INET; | ||
211 | sin_server.sin_addr.s_addr = in_aton(addr); | ||
212 | sin_server.sin_port = htons(v9ses->port); | ||
213 | sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket); | ||
214 | |||
215 | if (!csocket) { | ||
216 | eprintk(KERN_ERR, "v9fs_trans_tcp: problem creating socket\n"); | ||
217 | return -1; | ||
218 | } | ||
219 | |||
220 | ret = csocket->ops->connect(csocket, | ||
221 | (struct sockaddr *)&sin_server, | ||
222 | sizeof(struct sockaddr_in), 0); | ||
223 | if (ret < 0) { | ||
224 | eprintk(KERN_ERR, | ||
225 | "v9fs_trans_tcp: problem connecting socket to %s\n", | ||
226 | addr); | ||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | return v9fs_socket_open(v9ses, csocket); | ||
231 | } | ||
232 | |||
233 | static int | ||
234 | v9fs_unix_init(struct v9fs_session_info *v9ses, const char *addr, char *data) | ||
235 | { | ||
236 | int ret; | ||
237 | struct socket *csocket; | ||
238 | struct sockaddr_un sun_server; | ||
239 | |||
240 | if (strlen(addr) > UNIX_PATH_MAX) { | ||
241 | eprintk(KERN_ERR, "v9fs_trans_unix: address too long: %s\n", | ||
242 | addr); | ||
243 | return -ENAMETOOLONG; | ||
244 | } | ||
245 | |||
246 | sun_server.sun_family = PF_UNIX; | ||
247 | strcpy(sun_server.sun_path, addr); | ||
248 | sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket); | ||
249 | ret = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server, | ||
250 | sizeof(struct sockaddr_un) - 1, 0); | ||
251 | if (ret < 0) { | ||
252 | eprintk(KERN_ERR, | ||
253 | "v9fs_trans_unix: problem connecting socket: %s: %d\n", | ||
254 | addr, ret); | ||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | return v9fs_socket_open(v9ses, csocket); | ||
259 | } | ||
260 | |||
261 | /** | ||
262 | * v9fs_sock_close - shutdown socket | ||
263 | * @trans: private socket structure | ||
264 | * | ||
265 | */ | ||
266 | static void v9fs_fd_close(struct v9fs_transport *trans) | ||
267 | { | ||
268 | struct v9fs_trans_fd *ts; | ||
269 | |||
270 | if (!trans) | ||
271 | return; | ||
272 | |||
273 | ts = xchg(&trans->priv, NULL); | ||
274 | |||
275 | if (!ts) | ||
276 | return; | ||
277 | |||
278 | trans->status = Disconnected; | ||
279 | if (ts->rd) | ||
280 | fput(ts->rd); | ||
281 | if (ts->wr) | ||
282 | fput(ts->wr); | ||
283 | kfree(ts); | ||
284 | } | ||
285 | |||
286 | struct v9fs_transport v9fs_trans_fd = { | ||
287 | .init = v9fs_fd_init, | ||
288 | .write = v9fs_fd_write, | ||
289 | .read = v9fs_fd_read, | ||
290 | .close = v9fs_fd_close, | ||
291 | .poll = v9fs_fd_poll, | ||
292 | }; | ||
293 | |||
294 | struct v9fs_transport v9fs_trans_tcp = { | ||
295 | .init = v9fs_tcp_init, | ||
296 | .write = v9fs_fd_write, | ||
297 | .read = v9fs_fd_read, | ||
298 | .close = v9fs_fd_close, | ||
299 | .poll = v9fs_fd_poll, | ||
300 | }; | ||
301 | |||
302 | struct v9fs_transport v9fs_trans_unix = { | ||
303 | .init = v9fs_unix_init, | ||
304 | .write = v9fs_fd_write, | ||
305 | .read = v9fs_fd_read, | ||
306 | .close = v9fs_fd_close, | ||
307 | .poll = v9fs_fd_poll, | ||
308 | }; | ||
diff --git a/fs/9p/transport.h b/fs/9p/transport.h deleted file mode 100644 index b38a4b8a41ce..000000000000 --- a/fs/9p/transport.h +++ /dev/null | |||
@@ -1,45 +0,0 @@ | |||
1 | /* | ||
2 | * linux/fs/9p/transport.h | ||
3 | * | ||
4 | * Transport Definition | ||
5 | * | ||
6 | * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net> | ||
7 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | ||
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 | enum v9fs_transport_status { | ||
27 | Connected, | ||
28 | Disconnected, | ||
29 | Hung, | ||
30 | }; | ||
31 | |||
32 | struct v9fs_transport { | ||
33 | enum v9fs_transport_status status; | ||
34 | void *priv; | ||
35 | |||
36 | int (*init) (struct v9fs_session_info *, const char *, char *); | ||
37 | int (*write) (struct v9fs_transport *, void *, int); | ||
38 | int (*read) (struct v9fs_transport *, void *, int); | ||
39 | void (*close) (struct v9fs_transport *); | ||
40 | unsigned int (*poll)(struct v9fs_transport *, struct poll_table_struct *); | ||
41 | }; | ||
42 | |||
43 | extern struct v9fs_transport v9fs_trans_tcp; | ||
44 | extern struct v9fs_transport v9fs_trans_unix; | ||
45 | extern struct v9fs_transport v9fs_trans_fd; | ||
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 6ad6f192b6e4..4feb5ae63ecf 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c | |||
@@ -29,16 +29,12 @@ | |||
29 | #include <linux/sched.h> | 29 | #include <linux/sched.h> |
30 | #include <linux/parser.h> | 30 | #include <linux/parser.h> |
31 | #include <linux/idr.h> | 31 | #include <linux/idr.h> |
32 | 32 | #include <net/9p/9p.h> | |
33 | #include "debug.h" | 33 | #include <net/9p/transport.h> |
34 | #include <net/9p/conn.h> | ||
35 | #include <net/9p/client.h> | ||
34 | #include "v9fs.h" | 36 | #include "v9fs.h" |
35 | #include "9p.h" | ||
36 | #include "v9fs_vfs.h" | 37 | #include "v9fs_vfs.h" |
37 | #include "transport.h" | ||
38 | #include "mux.h" | ||
39 | |||
40 | /* TODO: sysfs or debugfs interface */ | ||
41 | int v9fs_debug_level = 0; /* feature-rific global debug level */ | ||
42 | 38 | ||
43 | /* | 39 | /* |
44 | * Option Parsing (code inspired by NFS code) | 40 | * Option Parsing (code inspired by NFS code) |
@@ -47,12 +43,12 @@ int v9fs_debug_level = 0; /* feature-rific global debug level */ | |||
47 | 43 | ||
48 | enum { | 44 | enum { |
49 | /* Options that take integer arguments */ | 45 | /* Options that take integer arguments */ |
50 | Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, Opt_debug, | 46 | Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, |
51 | Opt_rfdno, Opt_wfdno, | 47 | Opt_rfdno, Opt_wfdno, |
52 | /* String options */ | 48 | /* String options */ |
53 | Opt_uname, Opt_remotename, | 49 | Opt_uname, Opt_remotename, |
54 | /* Options that take no arguments */ | 50 | /* Options that take no arguments */ |
55 | Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd, | 51 | Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd, Opt_pci, |
56 | /* Cache options */ | 52 | /* Cache options */ |
57 | Opt_cache_loose, | 53 | Opt_cache_loose, |
58 | /* Error token */ | 54 | /* Error token */ |
@@ -67,12 +63,14 @@ static match_table_t tokens = { | |||
67 | {Opt_afid, "afid=%u"}, | 63 | {Opt_afid, "afid=%u"}, |
68 | {Opt_rfdno, "rfdno=%u"}, | 64 | {Opt_rfdno, "rfdno=%u"}, |
69 | {Opt_wfdno, "wfdno=%u"}, | 65 | {Opt_wfdno, "wfdno=%u"}, |
70 | {Opt_debug, "debug=%x"}, | ||
71 | {Opt_uname, "uname=%s"}, | 66 | {Opt_uname, "uname=%s"}, |
72 | {Opt_remotename, "aname=%s"}, | 67 | {Opt_remotename, "aname=%s"}, |
73 | {Opt_unix, "proto=unix"}, | 68 | {Opt_unix, "proto=unix"}, |
74 | {Opt_tcp, "proto=tcp"}, | 69 | {Opt_tcp, "proto=tcp"}, |
75 | {Opt_fd, "proto=fd"}, | 70 | {Opt_fd, "proto=fd"}, |
71 | #ifdef CONFIG_PCI_9P | ||
72 | {Opt_pci, "proto=pci"}, | ||
73 | #endif | ||
76 | {Opt_tcp, "tcp"}, | 74 | {Opt_tcp, "tcp"}, |
77 | {Opt_unix, "unix"}, | 75 | {Opt_unix, "unix"}, |
78 | {Opt_fd, "fd"}, | 76 | {Opt_fd, "fd"}, |
@@ -83,6 +81,8 @@ static match_table_t tokens = { | |||
83 | {Opt_err, NULL} | 81 | {Opt_err, NULL} |
84 | }; | 82 | }; |
85 | 83 | ||
84 | extern struct p9_transport *p9pci_trans_create(void); | ||
85 | |||
86 | /* | 86 | /* |
87 | * Parse option string. | 87 | * Parse option string. |
88 | */ | 88 | */ |
@@ -122,7 +122,7 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) | |||
122 | token = match_token(p, tokens, args); | 122 | token = match_token(p, tokens, args); |
123 | if (token < Opt_uname) { | 123 | if (token < Opt_uname) { |
124 | if ((ret = match_int(&args[0], &option)) < 0) { | 124 | if ((ret = match_int(&args[0], &option)) < 0) { |
125 | dprintk(DEBUG_ERROR, | 125 | P9_DPRINTK(P9_DEBUG_ERROR, |
126 | "integer field, but no integer?\n"); | 126 | "integer field, but no integer?\n"); |
127 | continue; | 127 | continue; |
128 | } | 128 | } |
@@ -149,15 +149,15 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) | |||
149 | case Opt_wfdno: | 149 | case Opt_wfdno: |
150 | v9ses->wfdno = option; | 150 | v9ses->wfdno = option; |
151 | break; | 151 | break; |
152 | case Opt_debug: | ||
153 | v9ses->debug = option; | ||
154 | break; | ||
155 | case Opt_tcp: | 152 | case Opt_tcp: |
156 | v9ses->proto = PROTO_TCP; | 153 | v9ses->proto = PROTO_TCP; |
157 | break; | 154 | break; |
158 | case Opt_unix: | 155 | case Opt_unix: |
159 | v9ses->proto = PROTO_UNIX; | 156 | v9ses->proto = PROTO_UNIX; |
160 | break; | 157 | break; |
158 | case Opt_pci: | ||
159 | v9ses->proto = PROTO_PCI; | ||
160 | break; | ||
161 | case Opt_fd: | 161 | case Opt_fd: |
162 | v9ses->proto = PROTO_FD; | 162 | v9ses->proto = PROTO_FD; |
163 | break; | 163 | break; |
@@ -183,82 +183,6 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) | |||
183 | } | 183 | } |
184 | 184 | ||
185 | /** | 185 | /** |
186 | * v9fs_inode2v9ses - safely extract v9fs session info from super block | ||
187 | * @inode: inode to extract information from | ||
188 | * | ||
189 | * Paranoid function to extract v9ses information from superblock, | ||
190 | * if anything is missing it will report an error. | ||
191 | * | ||
192 | */ | ||
193 | |||
194 | struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode) | ||
195 | { | ||
196 | return (inode->i_sb->s_fs_info); | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * v9fs_get_idpool - allocate numeric id from pool | ||
201 | * @p - pool to allocate from | ||
202 | * | ||
203 | * XXX - This seems to be an awful generic function, should it be in idr.c with | ||
204 | * the lock included in struct idr? | ||
205 | */ | ||
206 | |||
207 | int v9fs_get_idpool(struct v9fs_idpool *p) | ||
208 | { | ||
209 | int i = 0; | ||
210 | int error; | ||
211 | |||
212 | retry: | ||
213 | if (idr_pre_get(&p->pool, GFP_KERNEL) == 0) | ||
214 | return 0; | ||
215 | |||
216 | if (down_interruptible(&p->lock) == -EINTR) { | ||
217 | eprintk(KERN_WARNING, "Interrupted while locking\n"); | ||
218 | return -1; | ||
219 | } | ||
220 | |||
221 | /* no need to store exactly p, we just need something non-null */ | ||
222 | error = idr_get_new(&p->pool, p, &i); | ||
223 | up(&p->lock); | ||
224 | |||
225 | if (error == -EAGAIN) | ||
226 | goto retry; | ||
227 | else if (error) | ||
228 | return -1; | ||
229 | |||
230 | return i; | ||
231 | } | ||
232 | |||
233 | /** | ||
234 | * v9fs_put_idpool - release numeric id from pool | ||
235 | * @p - pool to allocate from | ||
236 | * | ||
237 | * XXX - This seems to be an awful generic function, should it be in idr.c with | ||
238 | * the lock included in struct idr? | ||
239 | */ | ||
240 | |||
241 | void v9fs_put_idpool(int id, struct v9fs_idpool *p) | ||
242 | { | ||
243 | if (down_interruptible(&p->lock) == -EINTR) { | ||
244 | eprintk(KERN_WARNING, "Interrupted while locking\n"); | ||
245 | return; | ||
246 | } | ||
247 | idr_remove(&p->pool, id); | ||
248 | up(&p->lock); | ||
249 | } | ||
250 | |||
251 | /** | ||
252 | * v9fs_check_idpool - check if the specified id is available | ||
253 | * @id - id to check | ||
254 | * @p - pool | ||
255 | */ | ||
256 | int v9fs_check_idpool(int id, struct v9fs_idpool *p) | ||
257 | { | ||
258 | return idr_find(&p->pool, id) != NULL; | ||
259 | } | ||
260 | |||
261 | /** | ||
262 | * v9fs_session_init - initialize session | 186 | * v9fs_session_init - initialize session |
263 | * @v9ses: session information structure | 187 | * @v9ses: session information structure |
264 | * @dev_name: device being mounted | 188 | * @dev_name: device being mounted |
@@ -266,25 +190,21 @@ int v9fs_check_idpool(int id, struct v9fs_idpool *p) | |||
266 | * | 190 | * |
267 | */ | 191 | */ |
268 | 192 | ||
269 | int | 193 | struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, |
270 | v9fs_session_init(struct v9fs_session_info *v9ses, | ||
271 | const char *dev_name, char *data) | 194 | const char *dev_name, char *data) |
272 | { | 195 | { |
273 | struct v9fs_fcall *fcall = NULL; | ||
274 | struct v9fs_transport *trans_proto; | ||
275 | int n = 0; | ||
276 | int newfid = -1; | ||
277 | int retval = -EINVAL; | 196 | int retval = -EINVAL; |
278 | struct v9fs_str *version; | 197 | struct p9_transport *trans; |
198 | struct p9_fid *fid; | ||
279 | 199 | ||
280 | v9ses->name = __getname(); | 200 | v9ses->name = __getname(); |
281 | if (!v9ses->name) | 201 | if (!v9ses->name) |
282 | return -ENOMEM; | 202 | return ERR_PTR(-ENOMEM); |
283 | 203 | ||
284 | v9ses->remotename = __getname(); | 204 | v9ses->remotename = __getname(); |
285 | if (!v9ses->remotename) { | 205 | if (!v9ses->remotename) { |
286 | __putname(v9ses->name); | 206 | __putname(v9ses->name); |
287 | return -ENOMEM; | 207 | return ERR_PTR(-ENOMEM); |
288 | } | 208 | } |
289 | 209 | ||
290 | strcpy(v9ses->name, V9FS_DEFUSER); | 210 | strcpy(v9ses->name, V9FS_DEFUSER); |
@@ -292,130 +212,60 @@ v9fs_session_init(struct v9fs_session_info *v9ses, | |||
292 | 212 | ||
293 | v9fs_parse_options(data, v9ses); | 213 | v9fs_parse_options(data, v9ses); |
294 | 214 | ||
295 | /* set global debug level */ | ||
296 | v9fs_debug_level = v9ses->debug; | ||
297 | |||
298 | /* id pools that are session-dependent: fids and tags */ | ||
299 | idr_init(&v9ses->fidpool.pool); | ||
300 | init_MUTEX(&v9ses->fidpool.lock); | ||
301 | |||
302 | switch (v9ses->proto) { | 215 | switch (v9ses->proto) { |
303 | case PROTO_TCP: | 216 | case PROTO_TCP: |
304 | trans_proto = &v9fs_trans_tcp; | 217 | trans = p9_trans_create_tcp(dev_name, v9ses->port); |
305 | break; | 218 | break; |
306 | case PROTO_UNIX: | 219 | case PROTO_UNIX: |
307 | trans_proto = &v9fs_trans_unix; | 220 | trans = p9_trans_create_unix(dev_name); |
308 | *v9ses->remotename = 0; | 221 | *v9ses->remotename = 0; |
309 | break; | 222 | break; |
310 | case PROTO_FD: | 223 | case PROTO_FD: |
311 | trans_proto = &v9fs_trans_fd; | 224 | trans = p9_trans_create_fd(v9ses->rfdno, v9ses->wfdno); |
225 | *v9ses->remotename = 0; | ||
226 | break; | ||
227 | #ifdef CONFIG_PCI_9P | ||
228 | case PROTO_PCI: | ||
229 | trans = p9pci_trans_create(); | ||
312 | *v9ses->remotename = 0; | 230 | *v9ses->remotename = 0; |
313 | break; | 231 | break; |
232 | #endif | ||
314 | default: | 233 | default: |
315 | printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto); | 234 | printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto); |
316 | retval = -ENOPROTOOPT; | 235 | retval = -ENOPROTOOPT; |
317 | goto SessCleanUp; | 236 | goto error; |
318 | }; | 237 | }; |
319 | 238 | ||
320 | v9ses->transport = kmalloc(sizeof(*v9ses->transport), GFP_KERNEL); | 239 | if (IS_ERR(trans)) { |
321 | if (!v9ses->transport) { | 240 | retval = PTR_ERR(trans); |
322 | retval = -ENOMEM; | 241 | trans = NULL; |
323 | goto SessCleanUp; | 242 | goto error; |
324 | } | 243 | } |
325 | 244 | ||
326 | memmove(v9ses->transport, trans_proto, sizeof(*v9ses->transport)); | 245 | v9ses->clnt = p9_client_create(trans, v9ses->maxdata + P9_IOHDRSZ, |
246 | v9ses->extended); | ||
327 | 247 | ||
328 | if ((retval = v9ses->transport->init(v9ses, dev_name, data)) < 0) { | 248 | if (IS_ERR(v9ses->clnt)) { |
329 | eprintk(KERN_ERR, "problem initializing transport\n"); | 249 | retval = PTR_ERR(v9ses->clnt); |
330 | goto SessCleanUp; | 250 | v9ses->clnt = NULL; |
251 | P9_DPRINTK(P9_DEBUG_ERROR, "problem initializing 9p client\n"); | ||
252 | goto error; | ||
331 | } | 253 | } |
332 | 254 | ||
333 | v9ses->inprogress = 0; | 255 | fid = p9_client_attach(v9ses->clnt, NULL, v9ses->name, |
334 | v9ses->shutdown = 0; | 256 | v9ses->remotename); |
335 | v9ses->session_hung = 0; | 257 | if (IS_ERR(fid)) { |
336 | 258 | retval = PTR_ERR(fid); | |
337 | v9ses->mux = v9fs_mux_init(v9ses->transport, v9ses->maxdata + V9FS_IOHDRSZ, | 259 | fid = NULL; |
338 | &v9ses->extended); | 260 | P9_DPRINTK(P9_DEBUG_ERROR, "cannot attach\n"); |
339 | 261 | goto error; | |
340 | if (IS_ERR(v9ses->mux)) { | ||
341 | retval = PTR_ERR(v9ses->mux); | ||
342 | v9ses->mux = NULL; | ||
343 | dprintk(DEBUG_ERROR, "problem initializing mux\n"); | ||
344 | goto SessCleanUp; | ||
345 | } | 262 | } |
346 | 263 | ||
347 | if (v9ses->afid == ~0) { | 264 | return fid; |
348 | if (v9ses->extended) | ||
349 | retval = | ||
350 | v9fs_t_version(v9ses, v9ses->maxdata, "9P2000.u", | ||
351 | &fcall); | ||
352 | else | ||
353 | retval = v9fs_t_version(v9ses, v9ses->maxdata, "9P2000", | ||
354 | &fcall); | ||
355 | |||
356 | if (retval < 0) { | ||
357 | dprintk(DEBUG_ERROR, "v9fs_t_version failed\n"); | ||
358 | goto FreeFcall; | ||
359 | } | ||
360 | |||
361 | version = &fcall->params.rversion.version; | ||
362 | if (version->len==8 && !memcmp(version->str, "9P2000.u", 8)) { | ||
363 | dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n"); | ||
364 | v9ses->extended = 1; | ||
365 | } else if (version->len==6 && !memcmp(version->str, "9P2000", 6)) { | ||
366 | dprintk(DEBUG_9P, "9P2000 legacy mode enabled\n"); | ||
367 | v9ses->extended = 0; | ||
368 | } else { | ||
369 | retval = -EREMOTEIO; | ||
370 | goto FreeFcall; | ||
371 | } | ||
372 | 265 | ||
373 | n = fcall->params.rversion.msize; | 266 | error: |
374 | kfree(fcall); | ||
375 | |||
376 | if (n < v9ses->maxdata) | ||
377 | v9ses->maxdata = n; | ||
378 | } | ||
379 | |||
380 | newfid = v9fs_get_idpool(&v9ses->fidpool); | ||
381 | if (newfid < 0) { | ||
382 | eprintk(KERN_WARNING, "couldn't allocate FID\n"); | ||
383 | retval = -ENOMEM; | ||
384 | goto SessCleanUp; | ||
385 | } | ||
386 | /* it is a little bit ugly, but we have to prevent newfid */ | ||
387 | /* being the same as afid, so if it is, get a new fid */ | ||
388 | if (v9ses->afid != ~0 && newfid == v9ses->afid) { | ||
389 | newfid = v9fs_get_idpool(&v9ses->fidpool); | ||
390 | if (newfid < 0) { | ||
391 | eprintk(KERN_WARNING, "couldn't allocate FID\n"); | ||
392 | retval = -ENOMEM; | ||
393 | goto SessCleanUp; | ||
394 | } | ||
395 | } | ||
396 | |||
397 | if ((retval = | ||
398 | v9fs_t_attach(v9ses, v9ses->name, v9ses->remotename, newfid, | ||
399 | v9ses->afid, NULL)) | ||
400 | < 0) { | ||
401 | dprintk(DEBUG_ERROR, "cannot attach\n"); | ||
402 | goto SessCleanUp; | ||
403 | } | ||
404 | |||
405 | if (v9ses->afid != ~0) { | ||
406 | dprintk(DEBUG_ERROR, "afid not equal to ~0\n"); | ||
407 | if (v9fs_t_clunk(v9ses, v9ses->afid)) | ||
408 | dprintk(DEBUG_ERROR, "clunk failed\n"); | ||
409 | } | ||
410 | |||
411 | return newfid; | ||
412 | |||
413 | FreeFcall: | ||
414 | kfree(fcall); | ||
415 | |||
416 | SessCleanUp: | ||
417 | v9fs_session_close(v9ses); | 267 | v9fs_session_close(v9ses); |
418 | return retval; | 268 | return ERR_PTR(retval); |
419 | } | 269 | } |
420 | 270 | ||
421 | /** | 271 | /** |
@@ -426,15 +276,9 @@ v9fs_session_init(struct v9fs_session_info *v9ses, | |||
426 | 276 | ||
427 | void v9fs_session_close(struct v9fs_session_info *v9ses) | 277 | void v9fs_session_close(struct v9fs_session_info *v9ses) |
428 | { | 278 | { |
429 | if (v9ses->mux) { | 279 | if (v9ses->clnt) { |
430 | v9fs_mux_destroy(v9ses->mux); | 280 | p9_client_destroy(v9ses->clnt); |
431 | v9ses->mux = NULL; | 281 | v9ses->clnt = NULL; |
432 | } | ||
433 | |||
434 | if (v9ses->transport) { | ||
435 | v9ses->transport->close(v9ses->transport); | ||
436 | kfree(v9ses->transport); | ||
437 | v9ses->transport = NULL; | ||
438 | } | 282 | } |
439 | 283 | ||
440 | __putname(v9ses->name); | 284 | __putname(v9ses->name); |
@@ -446,9 +290,8 @@ void v9fs_session_close(struct v9fs_session_info *v9ses) | |||
446 | * and cancel all pending requests. | 290 | * and cancel all pending requests. |
447 | */ | 291 | */ |
448 | void v9fs_session_cancel(struct v9fs_session_info *v9ses) { | 292 | void v9fs_session_cancel(struct v9fs_session_info *v9ses) { |
449 | dprintk(DEBUG_ERROR, "cancel session %p\n", v9ses); | 293 | P9_DPRINTK(P9_DEBUG_ERROR, "cancel session %p\n", v9ses); |
450 | v9ses->transport->status = Disconnected; | 294 | p9_client_disconnect(v9ses->clnt); |
451 | v9fs_mux_cancel(v9ses->mux, -EIO); | ||
452 | } | 295 | } |
453 | 296 | ||
454 | extern int v9fs_error_init(void); | 297 | extern int v9fs_error_init(void); |
@@ -460,24 +303,9 @@ extern int v9fs_error_init(void); | |||
460 | 303 | ||
461 | static int __init init_v9fs(void) | 304 | static int __init init_v9fs(void) |
462 | { | 305 | { |
463 | int ret; | ||
464 | |||
465 | v9fs_error_init(); | ||
466 | |||
467 | printk(KERN_INFO "Installing v9fs 9p2000 file system support\n"); | 306 | printk(KERN_INFO "Installing v9fs 9p2000 file system support\n"); |
468 | 307 | ||
469 | ret = v9fs_mux_global_init(); | 308 | return register_filesystem(&v9fs_fs_type); |
470 | if (ret) { | ||
471 | printk(KERN_WARNING "v9fs: starting mux failed\n"); | ||
472 | return ret; | ||
473 | } | ||
474 | ret = register_filesystem(&v9fs_fs_type); | ||
475 | if (ret) { | ||
476 | printk(KERN_WARNING "v9fs: registering file system failed\n"); | ||
477 | v9fs_mux_global_exit(); | ||
478 | } | ||
479 | |||
480 | return ret; | ||
481 | } | 309 | } |
482 | 310 | ||
483 | /** | 311 | /** |
@@ -487,13 +315,13 @@ static int __init init_v9fs(void) | |||
487 | 315 | ||
488 | static void __exit exit_v9fs(void) | 316 | static void __exit exit_v9fs(void) |
489 | { | 317 | { |
490 | v9fs_mux_global_exit(); | ||
491 | unregister_filesystem(&v9fs_fs_type); | 318 | unregister_filesystem(&v9fs_fs_type); |
492 | } | 319 | } |
493 | 320 | ||
494 | module_init(init_v9fs) | 321 | module_init(init_v9fs) |
495 | module_exit(exit_v9fs) | 322 | module_exit(exit_v9fs) |
496 | 323 | ||
324 | MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>"); | ||
497 | MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>"); | 325 | MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>"); |
498 | MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>"); | 326 | MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>"); |
499 | MODULE_LICENSE("GPL"); | 327 | MODULE_LICENSE("GPL"); |
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index 820bf5ca35d8..abc4b1668ace 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h | |||
@@ -22,16 +22,6 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * Idpool structure provides lock and id management | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | struct v9fs_idpool { | ||
30 | struct semaphore lock; | ||
31 | struct idr pool; | ||
32 | }; | ||
33 | |||
34 | /* | ||
35 | * Session structure provides information for an opened session | 25 | * Session structure provides information for an opened session |
36 | * | 26 | * |
37 | */ | 27 | */ |
@@ -54,15 +44,7 @@ struct v9fs_session_info { | |||
54 | unsigned int uid; /* default uid/muid for legacy support */ | 44 | unsigned int uid; /* default uid/muid for legacy support */ |
55 | unsigned int gid; /* default gid for legacy support */ | 45 | unsigned int gid; /* default gid for legacy support */ |
56 | 46 | ||
57 | /* book keeping */ | 47 | struct p9_client *clnt; /* 9p client */ |
58 | struct v9fs_idpool fidpool; /* The FID pool for file descriptors */ | ||
59 | |||
60 | struct v9fs_transport *transport; | ||
61 | struct v9fs_mux_data *mux; | ||
62 | |||
63 | int inprogress; /* session in progress => true */ | ||
64 | int shutdown; /* session shutting down. no more attaches. */ | ||
65 | unsigned char session_hung; | ||
66 | struct dentry *debugfs_dir; | 48 | struct dentry *debugfs_dir; |
67 | }; | 49 | }; |
68 | 50 | ||
@@ -71,6 +53,7 @@ enum { | |||
71 | PROTO_TCP, | 53 | PROTO_TCP, |
72 | PROTO_UNIX, | 54 | PROTO_UNIX, |
73 | PROTO_FD, | 55 | PROTO_FD, |
56 | PROTO_PCI, | ||
74 | }; | 57 | }; |
75 | 58 | ||
76 | /* possible values of ->cache */ | 59 | /* possible values of ->cache */ |
@@ -82,12 +65,9 @@ enum { | |||
82 | 65 | ||
83 | extern struct dentry *v9fs_debugfs_root; | 66 | extern struct dentry *v9fs_debugfs_root; |
84 | 67 | ||
85 | int v9fs_session_init(struct v9fs_session_info *, const char *, char *); | 68 | struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *, |
86 | struct v9fs_session_info *v9fs_inode2v9ses(struct inode *); | 69 | char *); |
87 | void v9fs_session_close(struct v9fs_session_info *v9ses); | 70 | void v9fs_session_close(struct v9fs_session_info *v9ses); |
88 | int v9fs_get_idpool(struct v9fs_idpool *p); | ||
89 | void v9fs_put_idpool(int id, struct v9fs_idpool *p); | ||
90 | int v9fs_check_idpool(int id, struct v9fs_idpool *p); | ||
91 | void v9fs_session_cancel(struct v9fs_session_info *v9ses); | 71 | void v9fs_session_cancel(struct v9fs_session_info *v9ses); |
92 | 72 | ||
93 | #define V9FS_MAGIC 0x01021997 | 73 | #define V9FS_MAGIC 0x01021997 |
@@ -97,3 +77,7 @@ void v9fs_session_cancel(struct v9fs_session_info *v9ses); | |||
97 | #define V9FS_DEFUSER "nobody" | 77 | #define V9FS_DEFUSER "nobody" |
98 | #define V9FS_DEFANAME "" | 78 | #define V9FS_DEFANAME "" |
99 | 79 | ||
80 | static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode) | ||
81 | { | ||
82 | return (inode->i_sb->s_fs_info); | ||
83 | } | ||
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index 6a82d39dc498..fd01d90cada5 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h | |||
@@ -45,10 +45,10 @@ extern struct dentry_operations v9fs_dentry_operations; | |||
45 | extern struct dentry_operations v9fs_cached_dentry_operations; | 45 | extern struct dentry_operations v9fs_cached_dentry_operations; |
46 | 46 | ||
47 | struct inode *v9fs_get_inode(struct super_block *sb, int mode); | 47 | struct inode *v9fs_get_inode(struct super_block *sb, int mode); |
48 | ino_t v9fs_qid2ino(struct v9fs_qid *qid); | 48 | ino_t v9fs_qid2ino(struct p9_qid *qid); |
49 | void v9fs_stat2inode(struct v9fs_stat *, struct inode *, struct super_block *); | 49 | void v9fs_stat2inode(struct p9_stat *, struct inode *, struct super_block *); |
50 | int v9fs_dir_release(struct inode *inode, struct file *filp); | 50 | int v9fs_dir_release(struct inode *inode, struct file *filp); |
51 | int v9fs_file_open(struct inode *inode, struct file *file); | 51 | int v9fs_file_open(struct inode *inode, struct file *file); |
52 | void v9fs_inode2stat(struct inode *inode, struct v9fs_stat *stat); | 52 | void v9fs_inode2stat(struct inode *inode, struct p9_stat *stat); |
53 | void v9fs_dentry_release(struct dentry *); | 53 | void v9fs_dentry_release(struct dentry *); |
54 | int v9fs_uflags2omode(int uflags); | 54 | int v9fs_uflags2omode(int uflags); |
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index 9ac4ffe9ac7d..6248f0e727a3 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c | |||
@@ -33,10 +33,10 @@ | |||
33 | #include <linux/pagemap.h> | 33 | #include <linux/pagemap.h> |
34 | #include <linux/idr.h> | 34 | #include <linux/idr.h> |
35 | #include <linux/sched.h> | 35 | #include <linux/sched.h> |
36 | #include <net/9p/9p.h> | ||
37 | #include <net/9p/client.h> | ||
36 | 38 | ||
37 | #include "debug.h" | ||
38 | #include "v9fs.h" | 39 | #include "v9fs.h" |
39 | #include "9p.h" | ||
40 | #include "v9fs_vfs.h" | 40 | #include "v9fs_vfs.h" |
41 | #include "fid.h" | 41 | #include "fid.h" |
42 | 42 | ||
@@ -50,55 +50,26 @@ | |||
50 | 50 | ||
51 | static int v9fs_vfs_readpage(struct file *filp, struct page *page) | 51 | static int v9fs_vfs_readpage(struct file *filp, struct page *page) |
52 | { | 52 | { |
53 | char *buffer = NULL; | 53 | int retval; |
54 | int retval = -EIO; | 54 | loff_t offset; |
55 | loff_t offset = page_offset(page); | 55 | char *buffer; |
56 | int count = PAGE_CACHE_SIZE; | 56 | struct p9_fid *fid; |
57 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
58 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | ||
59 | int rsize = v9ses->maxdata - V9FS_IOHDRSZ; | ||
60 | struct v9fs_fid *v9f = filp->private_data; | ||
61 | struct v9fs_fcall *fcall = NULL; | ||
62 | int fid = v9f->fid; | ||
63 | int total = 0; | ||
64 | int result = 0; | ||
65 | |||
66 | dprintk(DEBUG_VFS, "\n"); | ||
67 | 57 | ||
58 | P9_DPRINTK(P9_DEBUG_VFS, "\n"); | ||
59 | fid = filp->private_data; | ||
68 | buffer = kmap(page); | 60 | buffer = kmap(page); |
69 | do { | 61 | offset = page_offset(page); |
70 | if (count < rsize) | ||
71 | rsize = count; | ||
72 | |||
73 | result = v9fs_t_read(v9ses, fid, offset, rsize, &fcall); | ||
74 | |||
75 | if (result < 0) { | ||
76 | printk(KERN_ERR "v9fs_t_read returned %d\n", | ||
77 | result); | ||
78 | |||
79 | kfree(fcall); | ||
80 | goto UnmapAndUnlock; | ||
81 | } else | ||
82 | offset += result; | ||
83 | |||
84 | memcpy(buffer, fcall->params.rread.data, result); | ||
85 | |||
86 | count -= result; | ||
87 | buffer += result; | ||
88 | total += result; | ||
89 | |||
90 | kfree(fcall); | ||
91 | 62 | ||
92 | if (result < rsize) | 63 | retval = p9_client_readn(fid, buffer, offset, PAGE_CACHE_SIZE); |
93 | break; | 64 | if (retval < 0) |
94 | } while (count); | 65 | goto done; |
95 | 66 | ||
96 | memset(buffer, 0, count); | 67 | memset(buffer + retval, 0, PAGE_CACHE_SIZE - retval); |
97 | flush_dcache_page(page); | 68 | flush_dcache_page(page); |
98 | SetPageUptodate(page); | 69 | SetPageUptodate(page); |
99 | retval = 0; | 70 | retval = 0; |
100 | 71 | ||
101 | UnmapAndUnlock: | 72 | done: |
102 | kunmap(page); | 73 | kunmap(page); |
103 | unlock_page(page); | 74 | unlock_page(page); |
104 | return retval; | 75 | return retval; |
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index d93960429c09..f9534f18df0a 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c | |||
@@ -34,10 +34,10 @@ | |||
34 | #include <linux/namei.h> | 34 | #include <linux/namei.h> |
35 | #include <linux/idr.h> | 35 | #include <linux/idr.h> |
36 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
37 | #include <net/9p/9p.h> | ||
38 | #include <net/9p/client.h> | ||
37 | 39 | ||
38 | #include "debug.h" | ||
39 | #include "v9fs.h" | 40 | #include "v9fs.h" |
40 | #include "9p.h" | ||
41 | #include "v9fs_vfs.h" | 41 | #include "v9fs_vfs.h" |
42 | #include "fid.h" | 42 | #include "fid.h" |
43 | 43 | ||
@@ -52,7 +52,7 @@ | |||
52 | 52 | ||
53 | static int v9fs_dentry_delete(struct dentry *dentry) | 53 | static int v9fs_dentry_delete(struct dentry *dentry) |
54 | { | 54 | { |
55 | dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); | 55 | P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); |
56 | 56 | ||
57 | return 1; | 57 | return 1; |
58 | } | 58 | } |
@@ -69,7 +69,7 @@ static int v9fs_dentry_delete(struct dentry *dentry) | |||
69 | static int v9fs_cached_dentry_delete(struct dentry *dentry) | 69 | static int v9fs_cached_dentry_delete(struct dentry *dentry) |
70 | { | 70 | { |
71 | struct inode *inode = dentry->d_inode; | 71 | struct inode *inode = dentry->d_inode; |
72 | dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); | 72 | P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); |
73 | 73 | ||
74 | if(!inode) | 74 | if(!inode) |
75 | return 1; | 75 | return 1; |
@@ -85,26 +85,19 @@ static int v9fs_cached_dentry_delete(struct dentry *dentry) | |||
85 | 85 | ||
86 | void v9fs_dentry_release(struct dentry *dentry) | 86 | void v9fs_dentry_release(struct dentry *dentry) |
87 | { | 87 | { |
88 | int err; | 88 | struct v9fs_dentry *dent; |
89 | 89 | struct p9_fid *temp, *current_fid; | |
90 | dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); | 90 | |
91 | 91 | P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); | |
92 | if (dentry->d_fsdata != NULL) { | 92 | dent = dentry->d_fsdata; |
93 | struct list_head *fid_list = dentry->d_fsdata; | 93 | if (dent) { |
94 | struct v9fs_fid *temp = NULL; | 94 | list_for_each_entry_safe(current_fid, temp, &dent->fidlist, |
95 | struct v9fs_fid *current_fid = NULL; | 95 | dlist) { |
96 | 96 | p9_client_clunk(current_fid); | |
97 | list_for_each_entry_safe(current_fid, temp, fid_list, list) { | ||
98 | err = v9fs_t_clunk(current_fid->v9ses, current_fid->fid); | ||
99 | |||
100 | if (err < 0) | ||
101 | dprintk(DEBUG_ERROR, "clunk failed: %d name %s\n", | ||
102 | err, dentry->d_iname); | ||
103 | |||
104 | v9fs_fid_destroy(current_fid); | ||
105 | } | 97 | } |
106 | 98 | ||
107 | kfree(dentry->d_fsdata); /* free the list_head */ | 99 | kfree(dent); |
100 | dentry->d_fsdata = NULL; | ||
108 | } | 101 | } |
109 | } | 102 | } |
110 | 103 | ||
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 1dd86ee90bc5..0924d4477da3 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c | |||
@@ -32,11 +32,10 @@ | |||
32 | #include <linux/sched.h> | 32 | #include <linux/sched.h> |
33 | #include <linux/inet.h> | 33 | #include <linux/inet.h> |
34 | #include <linux/idr.h> | 34 | #include <linux/idr.h> |
35 | #include <net/9p/9p.h> | ||
36 | #include <net/9p/client.h> | ||
35 | 37 | ||
36 | #include "debug.h" | ||
37 | #include "v9fs.h" | 38 | #include "v9fs.h" |
38 | #include "9p.h" | ||
39 | #include "conv.h" | ||
40 | #include "v9fs_vfs.h" | 39 | #include "v9fs_vfs.h" |
41 | #include "fid.h" | 40 | #include "fid.h" |
42 | 41 | ||
@@ -46,14 +45,14 @@ | |||
46 | * | 45 | * |
47 | */ | 46 | */ |
48 | 47 | ||
49 | static inline int dt_type(struct v9fs_stat *mistat) | 48 | static inline int dt_type(struct p9_stat *mistat) |
50 | { | 49 | { |
51 | unsigned long perm = mistat->mode; | 50 | unsigned long perm = mistat->mode; |
52 | int rettype = DT_REG; | 51 | int rettype = DT_REG; |
53 | 52 | ||
54 | if (perm & V9FS_DMDIR) | 53 | if (perm & P9_DMDIR) |
55 | rettype = DT_DIR; | 54 | rettype = DT_DIR; |
56 | if (perm & V9FS_DMSYMLINK) | 55 | if (perm & P9_DMSYMLINK) |
57 | rettype = DT_LNK; | 56 | rettype = DT_LNK; |
58 | 57 | ||
59 | return rettype; | 58 | return rettype; |
@@ -69,106 +68,36 @@ static inline int dt_type(struct v9fs_stat *mistat) | |||
69 | 68 | ||
70 | static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) | 69 | static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) |
71 | { | 70 | { |
72 | struct v9fs_fcall *fcall = NULL; | 71 | int over; |
73 | struct inode *inode = filp->f_path.dentry->d_inode; | 72 | struct p9_fid *fid; |
74 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 73 | struct v9fs_session_info *v9ses; |
75 | struct v9fs_fid *file = filp->private_data; | 74 | struct inode *inode; |
76 | unsigned int i, n, s; | 75 | struct p9_stat *st; |
77 | int fid = -1; | 76 | |
78 | int ret = 0; | 77 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); |
79 | struct v9fs_stat stat; | 78 | inode = filp->f_path.dentry->d_inode; |
80 | int over = 0; | 79 | v9ses = v9fs_inode2v9ses(inode); |
81 | 80 | fid = filp->private_data; | |
82 | dprintk(DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); | 81 | while ((st = p9_client_dirread(fid, filp->f_pos)) != NULL) { |
83 | 82 | if (IS_ERR(st)) | |
84 | fid = file->fid; | 83 | return PTR_ERR(st); |
85 | 84 | ||
86 | if (file->rdir_fcall && (filp->f_pos != file->rdir_pos)) { | 85 | over = filldir(dirent, st->name.str, st->name.len, filp->f_pos, |
87 | kfree(file->rdir_fcall); | 86 | v9fs_qid2ino(&st->qid), dt_type(st)); |
88 | file->rdir_fcall = NULL; | 87 | |
89 | } | 88 | if (over) |
90 | |||
91 | if (file->rdir_fcall) { | ||
92 | n = file->rdir_fcall->params.rread.count; | ||
93 | i = file->rdir_fpos; | ||
94 | while (i < n) { | ||
95 | s = v9fs_deserialize_stat( | ||
96 | file->rdir_fcall->params.rread.data + i, | ||
97 | n - i, &stat, v9ses->extended); | ||
98 | |||
99 | if (s == 0) { | ||
100 | dprintk(DEBUG_ERROR, | ||
101 | "error while deserializing stat\n"); | ||
102 | ret = -EIO; | ||
103 | goto FreeStructs; | ||
104 | } | ||
105 | |||
106 | over = filldir(dirent, stat.name.str, stat.name.len, | ||
107 | filp->f_pos, v9fs_qid2ino(&stat.qid), | ||
108 | dt_type(&stat)); | ||
109 | |||
110 | if (over) { | ||
111 | file->rdir_fpos = i; | ||
112 | file->rdir_pos = filp->f_pos; | ||
113 | break; | ||
114 | } | ||
115 | |||
116 | i += s; | ||
117 | filp->f_pos += s; | ||
118 | } | ||
119 | |||
120 | if (!over) { | ||
121 | kfree(file->rdir_fcall); | ||
122 | file->rdir_fcall = NULL; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | while (!over) { | ||
127 | ret = v9fs_t_read(v9ses, fid, filp->f_pos, | ||
128 | v9ses->maxdata-V9FS_IOHDRSZ, &fcall); | ||
129 | if (ret < 0) { | ||
130 | dprintk(DEBUG_ERROR, "error while reading: %d: %p\n", | ||
131 | ret, fcall); | ||
132 | goto FreeStructs; | ||
133 | } else if (ret == 0) | ||
134 | break; | 89 | break; |
135 | 90 | ||
136 | n = ret; | 91 | filp->f_pos += st->size; |
137 | i = 0; | 92 | kfree(st); |
138 | while (i < n) { | 93 | st = NULL; |
139 | s = v9fs_deserialize_stat(fcall->params.rread.data + i, | ||
140 | n - i, &stat, v9ses->extended); | ||
141 | |||
142 | if (s == 0) { | ||
143 | dprintk(DEBUG_ERROR, | ||
144 | "error while deserializing stat\n"); | ||
145 | return -EIO; | ||
146 | } | ||
147 | |||
148 | over = filldir(dirent, stat.name.str, stat.name.len, | ||
149 | filp->f_pos, v9fs_qid2ino(&stat.qid), | ||
150 | dt_type(&stat)); | ||
151 | |||
152 | if (over) { | ||
153 | file->rdir_fcall = fcall; | ||
154 | file->rdir_fpos = i; | ||
155 | file->rdir_pos = filp->f_pos; | ||
156 | fcall = NULL; | ||
157 | break; | ||
158 | } | ||
159 | |||
160 | i += s; | ||
161 | filp->f_pos += s; | ||
162 | } | ||
163 | |||
164 | kfree(fcall); | ||
165 | } | 94 | } |
166 | 95 | ||
167 | FreeStructs: | 96 | kfree(st); |
168 | kfree(fcall); | 97 | return 0; |
169 | return ret; | ||
170 | } | 98 | } |
171 | 99 | ||
100 | |||
172 | /** | 101 | /** |
173 | * v9fs_dir_release - close a directory | 102 | * v9fs_dir_release - close a directory |
174 | * @inode: inode of the directory | 103 | * @inode: inode of the directory |
@@ -178,29 +107,13 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
178 | 107 | ||
179 | int v9fs_dir_release(struct inode *inode, struct file *filp) | 108 | int v9fs_dir_release(struct inode *inode, struct file *filp) |
180 | { | 109 | { |
181 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 110 | struct p9_fid *fid; |
182 | struct v9fs_fid *fid = filp->private_data; | ||
183 | int fidnum = -1; | ||
184 | |||
185 | dprintk(DEBUG_VFS, "inode: %p filp: %p fid: %d\n", inode, filp, | ||
186 | fid->fid); | ||
187 | fidnum = fid->fid; | ||
188 | 111 | ||
112 | fid = filp->private_data; | ||
113 | P9_DPRINTK(P9_DEBUG_VFS, | ||
114 | "inode: %p filp: %p fid: %d\n", inode, filp, fid->fid); | ||
189 | filemap_write_and_wait(inode->i_mapping); | 115 | filemap_write_and_wait(inode->i_mapping); |
190 | 116 | p9_client_clunk(fid); | |
191 | if (fidnum >= 0) { | ||
192 | dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen, | ||
193 | fid->fid); | ||
194 | |||
195 | if (v9fs_t_clunk(v9ses, fidnum)) | ||
196 | dprintk(DEBUG_ERROR, "clunk failed\n"); | ||
197 | |||
198 | kfree(fid->rdir_fcall); | ||
199 | kfree(fid); | ||
200 | |||
201 | filp->private_data = NULL; | ||
202 | } | ||
203 | |||
204 | return 0; | 117 | return 0; |
205 | } | 118 | } |
206 | 119 | ||
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 6e7678e4852f..c1f7c027cfeb 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c | |||
@@ -34,10 +34,10 @@ | |||
34 | #include <linux/list.h> | 34 | #include <linux/list.h> |
35 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
36 | #include <linux/idr.h> | 36 | #include <linux/idr.h> |
37 | #include <net/9p/9p.h> | ||
38 | #include <net/9p/client.h> | ||
37 | 39 | ||
38 | #include "debug.h" | ||
39 | #include "v9fs.h" | 40 | #include "v9fs.h" |
40 | #include "9p.h" | ||
41 | #include "v9fs_vfs.h" | 41 | #include "v9fs_vfs.h" |
42 | #include "fid.h" | 42 | #include "fid.h" |
43 | 43 | ||
@@ -52,48 +52,36 @@ static const struct file_operations v9fs_cached_file_operations; | |||
52 | 52 | ||
53 | int v9fs_file_open(struct inode *inode, struct file *file) | 53 | int v9fs_file_open(struct inode *inode, struct file *file) |
54 | { | 54 | { |
55 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | ||
56 | struct v9fs_fid *vfid; | ||
57 | struct v9fs_fcall *fcall = NULL; | ||
58 | int omode; | ||
59 | int err; | 55 | int err; |
56 | struct v9fs_session_info *v9ses; | ||
57 | struct p9_fid *fid; | ||
58 | int omode; | ||
60 | 59 | ||
61 | dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file); | 60 | P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p \n", inode, file); |
62 | 61 | v9ses = v9fs_inode2v9ses(inode); | |
63 | vfid = v9fs_fid_clone(file->f_path.dentry); | ||
64 | if (IS_ERR(vfid)) | ||
65 | return PTR_ERR(vfid); | ||
66 | |||
67 | omode = v9fs_uflags2omode(file->f_flags); | 62 | omode = v9fs_uflags2omode(file->f_flags); |
68 | err = v9fs_t_open(v9ses, vfid->fid, omode, &fcall); | 63 | fid = file->private_data; |
64 | if (!fid) { | ||
65 | fid = v9fs_fid_clone(file->f_path.dentry); | ||
66 | if (IS_ERR(fid)) | ||
67 | return PTR_ERR(fid); | ||
68 | |||
69 | err = p9_client_open(fid, omode); | ||
69 | if (err < 0) { | 70 | if (err < 0) { |
70 | PRINT_FCALL_ERROR("open failed", fcall); | 71 | p9_client_clunk(fid); |
71 | goto Clunk_Fid; | 72 | return err; |
73 | } | ||
72 | } | 74 | } |
73 | 75 | ||
74 | file->private_data = vfid; | 76 | file->private_data = fid; |
75 | vfid->fidopen = 1; | 77 | if ((fid->qid.version) && (v9ses->cache)) { |
76 | vfid->fidclunked = 0; | 78 | P9_DPRINTK(P9_DEBUG_VFS, "cached"); |
77 | vfid->iounit = fcall->params.ropen.iounit; | ||
78 | vfid->rdir_pos = 0; | ||
79 | vfid->rdir_fcall = NULL; | ||
80 | vfid->filp = file; | ||
81 | kfree(fcall); | ||
82 | |||
83 | if((vfid->qid.version) && (v9ses->cache)) { | ||
84 | dprintk(DEBUG_VFS, "cached"); | ||
85 | /* enable cached file options */ | 79 | /* enable cached file options */ |
86 | if(file->f_op == &v9fs_file_operations) | 80 | if(file->f_op == &v9fs_file_operations) |
87 | file->f_op = &v9fs_cached_file_operations; | 81 | file->f_op = &v9fs_cached_file_operations; |
88 | } | 82 | } |
89 | 83 | ||
90 | return 0; | 84 | return 0; |
91 | |||
92 | Clunk_Fid: | ||
93 | v9fs_fid_clunk(v9ses, vfid); | ||
94 | kfree(fcall); | ||
95 | |||
96 | return err; | ||
97 | } | 85 | } |
98 | 86 | ||
99 | /** | 87 | /** |
@@ -110,7 +98,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
110 | int res = 0; | 98 | int res = 0; |
111 | struct inode *inode = filp->f_path.dentry->d_inode; | 99 | struct inode *inode = filp->f_path.dentry->d_inode; |
112 | 100 | ||
113 | dprintk(DEBUG_VFS, "filp: %p lock: %p\n", filp, fl); | 101 | P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl); |
114 | 102 | ||
115 | /* No mandatory locks */ | 103 | /* No mandatory locks */ |
116 | if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) | 104 | if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) |
@@ -136,55 +124,16 @@ static ssize_t | |||
136 | v9fs_file_read(struct file *filp, char __user * data, size_t count, | 124 | v9fs_file_read(struct file *filp, char __user * data, size_t count, |
137 | loff_t * offset) | 125 | loff_t * offset) |
138 | { | 126 | { |
139 | struct inode *inode = filp->f_path.dentry->d_inode; | 127 | int ret; |
140 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 128 | struct p9_fid *fid; |
141 | struct v9fs_fid *v9f = filp->private_data; | ||
142 | struct v9fs_fcall *fcall = NULL; | ||
143 | int fid = v9f->fid; | ||
144 | int rsize = 0; | ||
145 | int result = 0; | ||
146 | int total = 0; | ||
147 | int n; | ||
148 | |||
149 | dprintk(DEBUG_VFS, "\n"); | ||
150 | |||
151 | rsize = v9ses->maxdata - V9FS_IOHDRSZ; | ||
152 | if (v9f->iounit != 0 && rsize > v9f->iounit) | ||
153 | rsize = v9f->iounit; | ||
154 | |||
155 | do { | ||
156 | if (count < rsize) | ||
157 | rsize = count; | ||
158 | 129 | ||
159 | result = v9fs_t_read(v9ses, fid, *offset, rsize, &fcall); | 130 | P9_DPRINTK(P9_DEBUG_VFS, "\n"); |
131 | fid = filp->private_data; | ||
132 | ret = p9_client_uread(fid, data, *offset, count); | ||
133 | if (ret > 0) | ||
134 | *offset += ret; | ||
160 | 135 | ||
161 | if (result < 0) { | 136 | return ret; |
162 | printk(KERN_ERR "9P2000: v9fs_t_read returned %d\n", | ||
163 | result); | ||
164 | |||
165 | kfree(fcall); | ||
166 | return total; | ||
167 | } else | ||
168 | *offset += result; | ||
169 | |||
170 | n = copy_to_user(data, fcall->params.rread.data, result); | ||
171 | if (n) { | ||
172 | dprintk(DEBUG_ERROR, "Problem copying to user %d\n", n); | ||
173 | kfree(fcall); | ||
174 | return -EFAULT; | ||
175 | } | ||
176 | |||
177 | count -= result; | ||
178 | data += result; | ||
179 | total += result; | ||
180 | |||
181 | kfree(fcall); | ||
182 | |||
183 | if (result < rsize) | ||
184 | break; | ||
185 | } while (count); | ||
186 | |||
187 | return total; | ||
188 | } | 137 | } |
189 | 138 | ||
190 | /** | 139 | /** |
@@ -200,50 +149,19 @@ static ssize_t | |||
200 | v9fs_file_write(struct file *filp, const char __user * data, | 149 | v9fs_file_write(struct file *filp, const char __user * data, |
201 | size_t count, loff_t * offset) | 150 | size_t count, loff_t * offset) |
202 | { | 151 | { |
203 | struct inode *inode = filp->f_path.dentry->d_inode; | 152 | int ret; |
204 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 153 | struct p9_fid *fid; |
205 | struct v9fs_fid *v9fid = filp->private_data; | ||
206 | struct v9fs_fcall *fcall; | ||
207 | int fid = v9fid->fid; | ||
208 | int result = -EIO; | ||
209 | int rsize = 0; | ||
210 | int total = 0; | ||
211 | |||
212 | dprintk(DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count, | ||
213 | (int)*offset); | ||
214 | rsize = v9ses->maxdata - V9FS_IOHDRSZ; | ||
215 | if (v9fid->iounit != 0 && rsize > v9fid->iounit) | ||
216 | rsize = v9fid->iounit; | ||
217 | |||
218 | do { | ||
219 | if (count < rsize) | ||
220 | rsize = count; | ||
221 | 154 | ||
222 | result = v9fs_t_write(v9ses, fid, *offset, rsize, data, &fcall); | 155 | P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data, |
223 | if (result < 0) { | 156 | (int)count, (int)*offset); |
224 | PRINT_FCALL_ERROR("error while writing", fcall); | ||
225 | kfree(fcall); | ||
226 | return result; | ||
227 | } else | ||
228 | *offset += result; | ||
229 | |||
230 | kfree(fcall); | ||
231 | fcall = NULL; | ||
232 | |||
233 | if (result != rsize) { | ||
234 | eprintk(KERN_ERR, | ||
235 | "short write: v9fs_t_write returned %d\n", | ||
236 | result); | ||
237 | break; | ||
238 | } | ||
239 | 157 | ||
240 | count -= result; | 158 | fid = filp->private_data; |
241 | data += result; | 159 | ret = p9_client_uwrite(fid, data, *offset, count); |
242 | total += result; | 160 | if (ret > 0) |
243 | } while (count); | 161 | *offset += ret; |
244 | 162 | ||
245 | invalidate_inode_pages2(inode->i_mapping); | 163 | invalidate_inode_pages2(filp->f_path.dentry->d_inode->i_mapping); |
246 | return total; | 164 | return ret; |
247 | } | 165 | } |
248 | 166 | ||
249 | static const struct file_operations v9fs_cached_file_operations = { | 167 | static const struct file_operations v9fs_cached_file_operations = { |
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index c76cd8fa3f6c..c602c0e054a2 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -34,10 +34,10 @@ | |||
34 | #include <linux/namei.h> | 34 | #include <linux/namei.h> |
35 | #include <linux/idr.h> | 35 | #include <linux/idr.h> |
36 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
37 | #include <net/9p/9p.h> | ||
38 | #include <net/9p/client.h> | ||
37 | 39 | ||
38 | #include "debug.h" | ||
39 | #include "v9fs.h" | 40 | #include "v9fs.h" |
40 | #include "9p.h" | ||
41 | #include "v9fs_vfs.h" | 41 | #include "v9fs_vfs.h" |
42 | #include "fid.h" | 42 | #include "fid.h" |
43 | 43 | ||
@@ -58,27 +58,27 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) | |||
58 | int res; | 58 | int res; |
59 | res = mode & 0777; | 59 | res = mode & 0777; |
60 | if (S_ISDIR(mode)) | 60 | if (S_ISDIR(mode)) |
61 | res |= V9FS_DMDIR; | 61 | res |= P9_DMDIR; |
62 | if (v9ses->extended) { | 62 | if (v9ses->extended) { |
63 | if (S_ISLNK(mode)) | 63 | if (S_ISLNK(mode)) |
64 | res |= V9FS_DMSYMLINK; | 64 | res |= P9_DMSYMLINK; |
65 | if (v9ses->nodev == 0) { | 65 | if (v9ses->nodev == 0) { |
66 | if (S_ISSOCK(mode)) | 66 | if (S_ISSOCK(mode)) |
67 | res |= V9FS_DMSOCKET; | 67 | res |= P9_DMSOCKET; |
68 | if (S_ISFIFO(mode)) | 68 | if (S_ISFIFO(mode)) |
69 | res |= V9FS_DMNAMEDPIPE; | 69 | res |= P9_DMNAMEDPIPE; |
70 | if (S_ISBLK(mode)) | 70 | if (S_ISBLK(mode)) |
71 | res |= V9FS_DMDEVICE; | 71 | res |= P9_DMDEVICE; |
72 | if (S_ISCHR(mode)) | 72 | if (S_ISCHR(mode)) |
73 | res |= V9FS_DMDEVICE; | 73 | res |= P9_DMDEVICE; |
74 | } | 74 | } |
75 | 75 | ||
76 | if ((mode & S_ISUID) == S_ISUID) | 76 | if ((mode & S_ISUID) == S_ISUID) |
77 | res |= V9FS_DMSETUID; | 77 | res |= P9_DMSETUID; |
78 | if ((mode & S_ISGID) == S_ISGID) | 78 | if ((mode & S_ISGID) == S_ISGID) |
79 | res |= V9FS_DMSETGID; | 79 | res |= P9_DMSETGID; |
80 | if ((mode & V9FS_DMLINK)) | 80 | if ((mode & P9_DMLINK)) |
81 | res |= V9FS_DMLINK; | 81 | res |= P9_DMLINK; |
82 | } | 82 | } |
83 | 83 | ||
84 | return res; | 84 | return res; |
@@ -97,27 +97,27 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) | |||
97 | 97 | ||
98 | res = mode & 0777; | 98 | res = mode & 0777; |
99 | 99 | ||
100 | if ((mode & V9FS_DMDIR) == V9FS_DMDIR) | 100 | if ((mode & P9_DMDIR) == P9_DMDIR) |
101 | res |= S_IFDIR; | 101 | res |= S_IFDIR; |
102 | else if ((mode & V9FS_DMSYMLINK) && (v9ses->extended)) | 102 | else if ((mode & P9_DMSYMLINK) && (v9ses->extended)) |
103 | res |= S_IFLNK; | 103 | res |= S_IFLNK; |
104 | else if ((mode & V9FS_DMSOCKET) && (v9ses->extended) | 104 | else if ((mode & P9_DMSOCKET) && (v9ses->extended) |
105 | && (v9ses->nodev == 0)) | 105 | && (v9ses->nodev == 0)) |
106 | res |= S_IFSOCK; | 106 | res |= S_IFSOCK; |
107 | else if ((mode & V9FS_DMNAMEDPIPE) && (v9ses->extended) | 107 | else if ((mode & P9_DMNAMEDPIPE) && (v9ses->extended) |
108 | && (v9ses->nodev == 0)) | 108 | && (v9ses->nodev == 0)) |
109 | res |= S_IFIFO; | 109 | res |= S_IFIFO; |
110 | else if ((mode & V9FS_DMDEVICE) && (v9ses->extended) | 110 | else if ((mode & P9_DMDEVICE) && (v9ses->extended) |
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 (v9ses->extended) { |
117 | if ((mode & V9FS_DMSETUID) == V9FS_DMSETUID) | 117 | if ((mode & P9_DMSETUID) == P9_DMSETUID) |
118 | res |= S_ISUID; | 118 | res |= S_ISUID; |
119 | 119 | ||
120 | if ((mode & V9FS_DMSETGID) == V9FS_DMSETGID) | 120 | if ((mode & P9_DMSETGID) == P9_DMSETGID) |
121 | res |= S_ISGID; | 121 | res |= S_ISGID; |
122 | } | 122 | } |
123 | 123 | ||
@@ -132,26 +132,26 @@ int v9fs_uflags2omode(int uflags) | |||
132 | switch (uflags&3) { | 132 | switch (uflags&3) { |
133 | default: | 133 | default: |
134 | case O_RDONLY: | 134 | case O_RDONLY: |
135 | ret = V9FS_OREAD; | 135 | ret = P9_OREAD; |
136 | break; | 136 | break; |
137 | 137 | ||
138 | case O_WRONLY: | 138 | case O_WRONLY: |
139 | ret = V9FS_OWRITE; | 139 | ret = P9_OWRITE; |
140 | break; | 140 | break; |
141 | 141 | ||
142 | case O_RDWR: | 142 | case O_RDWR: |
143 | ret = V9FS_ORDWR; | 143 | ret = P9_ORDWR; |
144 | break; | 144 | break; |
145 | } | 145 | } |
146 | 146 | ||
147 | if (uflags & O_EXCL) | 147 | if (uflags & O_EXCL) |
148 | ret |= V9FS_OEXCL; | 148 | ret |= P9_OEXCL; |
149 | 149 | ||
150 | if (uflags & O_TRUNC) | 150 | if (uflags & O_TRUNC) |
151 | ret |= V9FS_OTRUNC; | 151 | ret |= P9_OTRUNC; |
152 | 152 | ||
153 | if (uflags & O_APPEND) | 153 | if (uflags & O_APPEND) |
154 | ret |= V9FS_OAPPEND; | 154 | ret |= P9_OAPPEND; |
155 | 155 | ||
156 | return ret; | 156 | return ret; |
157 | } | 157 | } |
@@ -164,7 +164,7 @@ int v9fs_uflags2omode(int uflags) | |||
164 | */ | 164 | */ |
165 | 165 | ||
166 | static void | 166 | static void |
167 | v9fs_blank_wstat(struct v9fs_wstat *wstat) | 167 | v9fs_blank_wstat(struct p9_wstat *wstat) |
168 | { | 168 | { |
169 | wstat->type = ~0; | 169 | wstat->type = ~0; |
170 | wstat->dev = ~0; | 170 | wstat->dev = ~0; |
@@ -197,7 +197,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) | |||
197 | struct inode *inode; | 197 | struct inode *inode; |
198 | struct v9fs_session_info *v9ses = sb->s_fs_info; | 198 | struct v9fs_session_info *v9ses = sb->s_fs_info; |
199 | 199 | ||
200 | dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); | 200 | P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); |
201 | 201 | ||
202 | inode = new_inode(sb); | 202 | inode = new_inode(sb); |
203 | if (inode) { | 203 | if (inode) { |
@@ -215,7 +215,8 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) | |||
215 | case S_IFCHR: | 215 | case S_IFCHR: |
216 | case S_IFSOCK: | 216 | case S_IFSOCK: |
217 | if(!v9ses->extended) { | 217 | if(!v9ses->extended) { |
218 | dprintk(DEBUG_ERROR, "special files without extended mode\n"); | 218 | P9_DPRINTK(P9_DEBUG_ERROR, |
219 | "special files without extended mode\n"); | ||
219 | return ERR_PTR(-EINVAL); | 220 | return ERR_PTR(-EINVAL); |
220 | } | 221 | } |
221 | init_special_inode(inode, inode->i_mode, | 222 | init_special_inode(inode, inode->i_mode, |
@@ -227,7 +228,8 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) | |||
227 | break; | 228 | break; |
228 | case S_IFLNK: | 229 | case S_IFLNK: |
229 | if(!v9ses->extended) { | 230 | if(!v9ses->extended) { |
230 | dprintk(DEBUG_ERROR, "extended modes used w/o 9P2000.u\n"); | 231 | P9_DPRINTK(P9_DEBUG_ERROR, |
232 | "extended modes used w/o 9P2000.u\n"); | ||
231 | return ERR_PTR(-EINVAL); | 233 | return ERR_PTR(-EINVAL); |
232 | } | 234 | } |
233 | inode->i_op = &v9fs_symlink_inode_operations; | 235 | inode->i_op = &v9fs_symlink_inode_operations; |
@@ -241,71 +243,19 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) | |||
241 | inode->i_fop = &v9fs_dir_operations; | 243 | inode->i_fop = &v9fs_dir_operations; |
242 | break; | 244 | break; |
243 | default: | 245 | default: |
244 | dprintk(DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n", | 246 | P9_DPRINTK(P9_DEBUG_ERROR, |
247 | "BAD mode 0x%x S_IFMT 0x%x\n", | ||
245 | mode, mode & S_IFMT); | 248 | mode, mode & S_IFMT); |
246 | return ERR_PTR(-EINVAL); | 249 | return ERR_PTR(-EINVAL); |
247 | } | 250 | } |
248 | } else { | 251 | } else { |
249 | eprintk(KERN_WARNING, "Problem allocating inode\n"); | 252 | P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n"); |
250 | return ERR_PTR(-ENOMEM); | 253 | return ERR_PTR(-ENOMEM); |
251 | } | 254 | } |
252 | return inode; | 255 | return inode; |
253 | } | 256 | } |
254 | 257 | ||
255 | static int | 258 | /* |
256 | v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name, u32 perm, | ||
257 | u8 mode, char *extension, u32 *fidp, struct v9fs_qid *qid, u32 *iounit) | ||
258 | { | ||
259 | int fid; | ||
260 | int err; | ||
261 | struct v9fs_fcall *fcall; | ||
262 | |||
263 | fid = v9fs_get_idpool(&v9ses->fidpool); | ||
264 | if (fid < 0) { | ||
265 | eprintk(KERN_WARNING, "no free fids available\n"); | ||
266 | return -ENOSPC; | ||
267 | } | ||
268 | |||
269 | err = v9fs_t_walk(v9ses, pfid, fid, NULL, &fcall); | ||
270 | if (err < 0) { | ||
271 | PRINT_FCALL_ERROR("clone error", fcall); | ||
272 | if (fcall && fcall->id == RWALK) | ||
273 | goto clunk_fid; | ||
274 | else | ||
275 | goto put_fid; | ||
276 | } | ||
277 | kfree(fcall); | ||
278 | |||
279 | err = v9fs_t_create(v9ses, fid, name, perm, mode, extension, &fcall); | ||
280 | if (err < 0) { | ||
281 | PRINT_FCALL_ERROR("create fails", fcall); | ||
282 | goto clunk_fid; | ||
283 | } | ||
284 | |||
285 | if (iounit) | ||
286 | *iounit = fcall->params.rcreate.iounit; | ||
287 | |||
288 | if (qid) | ||
289 | *qid = fcall->params.rcreate.qid; | ||
290 | |||
291 | if (fidp) | ||
292 | *fidp = fid; | ||
293 | |||
294 | kfree(fcall); | ||
295 | return 0; | ||
296 | |||
297 | clunk_fid: | ||
298 | v9fs_t_clunk(v9ses, fid); | ||
299 | fid = V9FS_NOFID; | ||
300 | |||
301 | put_fid: | ||
302 | if (fid != V9FS_NOFID) | ||
303 | v9fs_put_idpool(fid, &v9ses->fidpool); | ||
304 | |||
305 | kfree(fcall); | ||
306 | return err; | ||
307 | } | ||
308 | |||
309 | static struct v9fs_fid* | 259 | static struct v9fs_fid* |
310 | v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry) | 260 | v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry) |
311 | { | 261 | { |
@@ -355,23 +305,25 @@ error: | |||
355 | kfree(fcall); | 305 | kfree(fcall); |
356 | return ERR_PTR(err); | 306 | return ERR_PTR(err); |
357 | } | 307 | } |
308 | */ | ||
358 | 309 | ||
359 | static struct inode * | 310 | static struct inode * |
360 | v9fs_inode_from_fid(struct v9fs_session_info *v9ses, u32 fid, | 311 | v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, |
361 | struct super_block *sb) | 312 | struct super_block *sb) |
362 | { | 313 | { |
363 | int err, umode; | 314 | int err, umode; |
364 | struct inode *ret; | 315 | struct inode *ret; |
365 | struct v9fs_fcall *fcall; | 316 | struct p9_stat *st; |
366 | 317 | ||
367 | ret = NULL; | 318 | ret = NULL; |
368 | err = v9fs_t_stat(v9ses, fid, &fcall); | 319 | st = p9_client_stat(fid); |
369 | if (err) { | 320 | if (IS_ERR(st)) { |
370 | PRINT_FCALL_ERROR("stat error", fcall); | 321 | err = PTR_ERR(st); |
322 | st = NULL; | ||
371 | goto error; | 323 | goto error; |
372 | } | 324 | } |
373 | 325 | ||
374 | umode = p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode); | 326 | umode = p9mode2unixmode(v9ses, st->mode); |
375 | ret = v9fs_get_inode(sb, umode); | 327 | ret = v9fs_get_inode(sb, umode); |
376 | if (IS_ERR(ret)) { | 328 | if (IS_ERR(ret)) { |
377 | err = PTR_ERR(ret); | 329 | err = PTR_ERR(ret); |
@@ -379,12 +331,13 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, u32 fid, | |||
379 | goto error; | 331 | goto error; |
380 | } | 332 | } |
381 | 333 | ||
382 | v9fs_stat2inode(&fcall->params.rstat.stat, ret, sb); | 334 | v9fs_stat2inode(st, ret, sb); |
383 | kfree(fcall); | 335 | ret->i_ino = v9fs_qid2ino(&st->qid); |
336 | kfree(st); | ||
384 | return ret; | 337 | return ret; |
385 | 338 | ||
386 | error: | 339 | error: |
387 | kfree(fcall); | 340 | kfree(st); |
388 | if (ret) | 341 | if (ret) |
389 | iput(ret); | 342 | iput(ret); |
390 | 343 | ||
@@ -401,43 +354,20 @@ error: | |||
401 | 354 | ||
402 | static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) | 355 | static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) |
403 | { | 356 | { |
404 | struct v9fs_fcall *fcall = NULL; | 357 | struct inode *file_inode; |
405 | struct super_block *sb = NULL; | 358 | struct v9fs_session_info *v9ses; |
406 | struct v9fs_session_info *v9ses = NULL; | 359 | struct p9_fid *v9fid; |
407 | struct v9fs_fid *v9fid = NULL; | ||
408 | struct inode *file_inode = NULL; | ||
409 | int fid = -1; | ||
410 | int result = 0; | ||
411 | 360 | ||
412 | dprintk(DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, | 361 | P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, |
413 | rmdir); | 362 | rmdir); |
414 | 363 | ||
415 | file_inode = file->d_inode; | 364 | file_inode = file->d_inode; |
416 | sb = file_inode->i_sb; | ||
417 | v9ses = v9fs_inode2v9ses(file_inode); | 365 | v9ses = v9fs_inode2v9ses(file_inode); |
418 | v9fid = v9fs_fid_clone(file); | 366 | v9fid = v9fs_fid_clone(file); |
419 | if(IS_ERR(v9fid)) | 367 | if(IS_ERR(v9fid)) |
420 | return PTR_ERR(v9fid); | 368 | return PTR_ERR(v9fid); |
421 | 369 | ||
422 | fid = v9fid->fid; | 370 | return p9_client_remove(v9fid); |
423 | if (fid < 0) { | ||
424 | dprintk(DEBUG_ERROR, "inode #%lu, no fid!\n", | ||
425 | file_inode->i_ino); | ||
426 | return -EBADF; | ||
427 | } | ||
428 | |||
429 | result = v9fs_t_remove(v9ses, fid, &fcall); | ||
430 | if (result < 0) { | ||
431 | PRINT_FCALL_ERROR("remove fails", fcall); | ||
432 | goto Error; | ||
433 | } | ||
434 | |||
435 | v9fs_put_idpool(fid, &v9ses->fidpool); | ||
436 | v9fs_fid_destroy(v9fid); | ||
437 | |||
438 | Error: | ||
439 | kfree(fcall); | ||
440 | return result; | ||
441 | } | 371 | } |
442 | 372 | ||
443 | static int | 373 | static int |
@@ -446,61 +376,59 @@ v9fs_open_created(struct inode *inode, struct file *file) | |||
446 | return 0; | 376 | return 0; |
447 | } | 377 | } |
448 | 378 | ||
379 | |||
449 | /** | 380 | /** |
450 | * v9fs_vfs_create - VFS hook to create files | 381 | * v9fs_create - Create a file |
451 | * @inode: directory inode that is being deleted | 382 | * @dentry: dentry that is being created |
452 | * @dentry: dentry that is being deleted | 383 | * @perm: create permissions |
453 | * @mode: create permissions | 384 | * @mode: open mode |
454 | * @nd: path information | ||
455 | * | 385 | * |
456 | */ | 386 | */ |
457 | 387 | static struct p9_fid * | |
458 | static int | 388 | v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, |
459 | v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, | 389 | struct dentry *dentry, char *extension, u32 perm, u8 mode) |
460 | struct nameidata *nd) | ||
461 | { | 390 | { |
462 | int err; | 391 | int err; |
463 | u32 fid, perm, iounit; | 392 | char *name; |
464 | int flags; | 393 | struct p9_fid *dfid, *ofid, *fid; |
465 | struct v9fs_session_info *v9ses; | ||
466 | struct v9fs_fid *dfid, *vfid, *ffid; | ||
467 | struct inode *inode; | 394 | struct inode *inode; |
468 | struct v9fs_qid qid; | ||
469 | struct file *filp; | ||
470 | 395 | ||
471 | inode = NULL; | 396 | err = 0; |
472 | vfid = NULL; | 397 | ofid = NULL; |
473 | v9ses = v9fs_inode2v9ses(dir); | 398 | fid = NULL; |
399 | name = (char *) dentry->d_name.name; | ||
474 | dfid = v9fs_fid_clone(dentry->d_parent); | 400 | dfid = v9fs_fid_clone(dentry->d_parent); |
475 | if(IS_ERR(dfid)) { | 401 | if(IS_ERR(dfid)) { |
476 | err = PTR_ERR(dfid); | 402 | err = PTR_ERR(dfid); |
403 | dfid = NULL; | ||
477 | goto error; | 404 | goto error; |
478 | } | 405 | } |
479 | 406 | ||
480 | perm = unixmode2p9mode(v9ses, mode); | 407 | /* clone a fid to use for creation */ |
481 | if (nd && nd->flags & LOOKUP_OPEN) | 408 | ofid = p9_client_walk(dfid, 0, NULL, 1); |
482 | flags = nd->intent.open.flags - 1; | 409 | if (IS_ERR(ofid)) { |
483 | else | 410 | err = PTR_ERR(ofid); |
484 | flags = O_RDWR; | 411 | ofid = NULL; |
485 | 412 | goto error; | |
486 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, | 413 | } |
487 | perm, v9fs_uflags2omode(flags), NULL, &fid, &qid, &iounit); | ||
488 | 414 | ||
489 | if (err) | 415 | err = p9_client_fcreate(ofid, name, perm, mode, extension); |
490 | goto clunk_dfid; | 416 | if (err < 0) |
417 | goto error; | ||
491 | 418 | ||
492 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); | 419 | /* now walk from the parent so we can get unopened fid */ |
493 | v9fs_fid_clunk(v9ses, dfid); | 420 | fid = p9_client_walk(dfid, 1, &name, 0); |
494 | if (IS_ERR(vfid)) { | 421 | if (IS_ERR(fid)) { |
495 | err = PTR_ERR(vfid); | 422 | err = PTR_ERR(fid); |
496 | vfid = NULL; | 423 | fid = NULL; |
497 | goto error; | 424 | goto error; |
498 | } | 425 | } else |
426 | dfid = NULL; | ||
499 | 427 | ||
500 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); | 428 | /* instantiate inode and assign the unopened fid to the dentry */ |
429 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | ||
501 | if (IS_ERR(inode)) { | 430 | if (IS_ERR(inode)) { |
502 | err = PTR_ERR(inode); | 431 | err = PTR_ERR(inode); |
503 | inode = NULL; | ||
504 | goto error; | 432 | goto error; |
505 | } | 433 | } |
506 | 434 | ||
@@ -508,35 +436,78 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
508 | dentry->d_op = &v9fs_cached_dentry_operations; | 436 | dentry->d_op = &v9fs_cached_dentry_operations; |
509 | else | 437 | else |
510 | dentry->d_op = &v9fs_dentry_operations; | 438 | dentry->d_op = &v9fs_dentry_operations; |
439 | |||
511 | d_instantiate(dentry, inode); | 440 | d_instantiate(dentry, inode); |
441 | v9fs_fid_add(dentry, fid); | ||
442 | return ofid; | ||
512 | 443 | ||
513 | if (nd && nd->flags & LOOKUP_OPEN) { | 444 | error: |
514 | ffid = v9fs_fid_create(v9ses, fid); | 445 | if (dfid) |
515 | if (!ffid) | 446 | p9_client_clunk(dfid); |
516 | return -ENOMEM; | 447 | |
448 | if (ofid) | ||
449 | p9_client_clunk(ofid); | ||
450 | |||
451 | if (fid) | ||
452 | p9_client_clunk(fid); | ||
453 | |||
454 | return ERR_PTR(err); | ||
455 | } | ||
456 | |||
457 | /** | ||
458 | * v9fs_vfs_create - VFS hook to create files | ||
459 | * @inode: directory inode that is being created | ||
460 | * @dentry: dentry that is being deleted | ||
461 | * @mode: create permissions | ||
462 | * @nd: path information | ||
463 | * | ||
464 | */ | ||
517 | 465 | ||
466 | static int | ||
467 | v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, | ||
468 | struct nameidata *nd) | ||
469 | { | ||
470 | int err; | ||
471 | u32 perm; | ||
472 | int flags; | ||
473 | struct v9fs_session_info *v9ses; | ||
474 | struct p9_fid *fid; | ||
475 | struct file *filp; | ||
476 | |||
477 | err = 0; | ||
478 | fid = NULL; | ||
479 | v9ses = v9fs_inode2v9ses(dir); | ||
480 | perm = unixmode2p9mode(v9ses, mode); | ||
481 | if (nd && nd->flags & LOOKUP_OPEN) | ||
482 | flags = nd->intent.open.flags - 1; | ||
483 | else | ||
484 | flags = O_RDWR; | ||
485 | |||
486 | fid = v9fs_create(v9ses, dir, dentry, NULL, perm, | ||
487 | v9fs_uflags2omode(flags)); | ||
488 | if (IS_ERR(fid)) { | ||
489 | err = PTR_ERR(fid); | ||
490 | fid = NULL; | ||
491 | goto error; | ||
492 | } | ||
493 | |||
494 | /* if we are opening a file, assign the open fid to the file */ | ||
495 | if (nd && nd->flags & LOOKUP_OPEN) { | ||
518 | filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); | 496 | filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); |
519 | if (IS_ERR(filp)) { | 497 | if (IS_ERR(filp)) { |
520 | v9fs_fid_destroy(ffid); | 498 | err = PTR_ERR(filp); |
521 | return PTR_ERR(filp); | 499 | goto error; |
522 | } | 500 | } |
523 | 501 | ||
524 | ffid->rdir_pos = 0; | 502 | filp->private_data = fid; |
525 | ffid->rdir_fcall = NULL; | 503 | } else |
526 | ffid->fidopen = 1; | 504 | p9_client_clunk(fid); |
527 | ffid->iounit = iounit; | ||
528 | ffid->filp = filp; | ||
529 | filp->private_data = ffid; | ||
530 | } | ||
531 | 505 | ||
532 | return 0; | 506 | return 0; |
533 | 507 | ||
534 | clunk_dfid: | ||
535 | v9fs_fid_clunk(v9ses, dfid); | ||
536 | |||
537 | error: | 508 | error: |
538 | if (vfid) | 509 | if (fid) |
539 | v9fs_fid_destroy(vfid); | 510 | p9_client_clunk(fid); |
540 | 511 | ||
541 | return err; | 512 | return err; |
542 | } | 513 | } |
@@ -552,57 +523,23 @@ error: | |||
552 | static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | 523 | static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) |
553 | { | 524 | { |
554 | int err; | 525 | int err; |
555 | u32 fid, perm; | 526 | u32 perm; |
556 | struct v9fs_session_info *v9ses; | 527 | struct v9fs_session_info *v9ses; |
557 | struct v9fs_fid *dfid, *vfid; | 528 | struct p9_fid *fid; |
558 | struct inode *inode; | ||
559 | 529 | ||
560 | inode = NULL; | 530 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name); |
561 | vfid = NULL; | 531 | err = 0; |
562 | v9ses = v9fs_inode2v9ses(dir); | 532 | v9ses = v9fs_inode2v9ses(dir); |
563 | dfid = v9fs_fid_clone(dentry->d_parent); | ||
564 | if(IS_ERR(dfid)) { | ||
565 | err = PTR_ERR(dfid); | ||
566 | goto error; | ||
567 | } | ||
568 | |||
569 | perm = unixmode2p9mode(v9ses, mode | S_IFDIR); | 533 | perm = unixmode2p9mode(v9ses, mode | S_IFDIR); |
570 | 534 | fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_OREAD); | |
571 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, | 535 | if (IS_ERR(fid)) { |
572 | perm, V9FS_OREAD, NULL, &fid, NULL, NULL); | 536 | err = PTR_ERR(fid); |
573 | 537 | fid = NULL; | |
574 | if (err) { | ||
575 | dprintk(DEBUG_ERROR, "create error %d\n", err); | ||
576 | goto clean_up_dfid; | ||
577 | } | 538 | } |
578 | 539 | ||
579 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); | 540 | if (fid) |
580 | if (IS_ERR(vfid)) { | 541 | p9_client_clunk(fid); |
581 | err = PTR_ERR(vfid); | ||
582 | vfid = NULL; | ||
583 | goto clean_up_dfid; | ||
584 | } | ||
585 | 542 | ||
586 | v9fs_fid_clunk(v9ses, dfid); | ||
587 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); | ||
588 | if (IS_ERR(inode)) { | ||
589 | err = PTR_ERR(inode); | ||
590 | inode = NULL; | ||
591 | v9fs_fid_destroy(vfid); | ||
592 | goto error; | ||
593 | } | ||
594 | |||
595 | if(v9ses->cache) | ||
596 | dentry->d_op = &v9fs_cached_dentry_operations; | ||
597 | else | ||
598 | dentry->d_op = &v9fs_dentry_operations; | ||
599 | d_instantiate(dentry, inode); | ||
600 | return 0; | ||
601 | |||
602 | clean_up_dfid: | ||
603 | v9fs_fid_clunk(v9ses, dfid); | ||
604 | |||
605 | error: | ||
606 | return err; | 543 | return err; |
607 | } | 544 | } |
608 | 545 | ||
@@ -619,104 +556,54 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
619 | { | 556 | { |
620 | struct super_block *sb; | 557 | struct super_block *sb; |
621 | struct v9fs_session_info *v9ses; | 558 | struct v9fs_session_info *v9ses; |
622 | struct v9fs_fid *dirfid; | 559 | struct p9_fid *dfid, *fid; |
623 | struct v9fs_fid *fid; | ||
624 | struct inode *inode; | 560 | struct inode *inode; |
625 | struct v9fs_fcall *fcall = NULL; | 561 | char *name; |
626 | int dirfidnum = -1; | ||
627 | int newfid = -1; | ||
628 | int result = 0; | 562 | int result = 0; |
629 | 563 | ||
630 | dprintk(DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", | 564 | P9_DPRINTK(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", |
631 | dir, dentry->d_name.name, dentry, nameidata); | 565 | dir, dentry->d_name.name, dentry, nameidata); |
632 | 566 | ||
633 | sb = dir->i_sb; | 567 | sb = dir->i_sb; |
634 | v9ses = v9fs_inode2v9ses(dir); | 568 | v9ses = v9fs_inode2v9ses(dir); |
635 | dirfid = v9fs_fid_lookup(dentry->d_parent); | 569 | dfid = v9fs_fid_lookup(dentry->d_parent); |
636 | 570 | if (IS_ERR(dfid)) | |
637 | if(IS_ERR(dirfid)) | 571 | return ERR_PTR(PTR_ERR(dfid)); |
638 | return ERR_PTR(PTR_ERR(dirfid)); | 572 | |
639 | 573 | name = (char *) dentry->d_name.name; | |
640 | dirfidnum = dirfid->fid; | 574 | fid = p9_client_walk(dfid, 1, &name, 1); |
641 | 575 | if (IS_ERR(fid)) { | |
642 | newfid = v9fs_get_idpool(&v9ses->fidpool); | 576 | result = PTR_ERR(fid); |
643 | if (newfid < 0) { | ||
644 | eprintk(KERN_WARNING, "newfid fails!\n"); | ||
645 | result = -ENOSPC; | ||
646 | goto Release_Dirfid; | ||
647 | } | ||
648 | |||
649 | result = v9fs_t_walk(v9ses, dirfidnum, newfid, | ||
650 | (char *)dentry->d_name.name, &fcall); | ||
651 | |||
652 | up(&dirfid->lock); | ||
653 | |||
654 | if (result < 0) { | ||
655 | if (fcall && fcall->id == RWALK) | ||
656 | v9fs_t_clunk(v9ses, newfid); | ||
657 | else | ||
658 | v9fs_put_idpool(newfid, &v9ses->fidpool); | ||
659 | |||
660 | if (result == -ENOENT) { | 577 | if (result == -ENOENT) { |
661 | d_add(dentry, NULL); | 578 | d_add(dentry, NULL); |
662 | dprintk(DEBUG_VFS, | ||
663 | "Return negative dentry %p count %d\n", | ||
664 | dentry, atomic_read(&dentry->d_count)); | ||
665 | kfree(fcall); | ||
666 | return NULL; | 579 | return NULL; |
667 | } | 580 | } |
668 | dprintk(DEBUG_ERROR, "walk error:%d\n", result); | ||
669 | goto FreeFcall; | ||
670 | } | ||
671 | kfree(fcall); | ||
672 | |||
673 | result = v9fs_t_stat(v9ses, newfid, &fcall); | ||
674 | if (result < 0) { | ||
675 | dprintk(DEBUG_ERROR, "stat error\n"); | ||
676 | goto FreeFcall; | ||
677 | } | ||
678 | |||
679 | inode = v9fs_get_inode(sb, p9mode2unixmode(v9ses, | ||
680 | fcall->params.rstat.stat.mode)); | ||
681 | 581 | ||
682 | if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) { | 582 | return ERR_PTR(result); |
683 | eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n", | ||
684 | PTR_ERR(inode)); | ||
685 | |||
686 | result = -ENOSPC; | ||
687 | goto FreeFcall; | ||
688 | } | 583 | } |
689 | 584 | ||
690 | inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid); | 585 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); |
691 | 586 | if (IS_ERR(inode)) { | |
692 | fid = v9fs_fid_create(v9ses, newfid); | 587 | result = PTR_ERR(inode); |
693 | if (fid == NULL) { | 588 | inode = NULL; |
694 | dprintk(DEBUG_ERROR, "couldn't insert\n"); | 589 | goto error; |
695 | result = -ENOMEM; | ||
696 | goto FreeFcall; | ||
697 | } | 590 | } |
698 | 591 | ||
699 | result = v9fs_fid_insert(fid, dentry); | 592 | result = v9fs_fid_add(dentry, fid); |
700 | if (result < 0) | 593 | if (result < 0) |
701 | goto FreeFcall; | 594 | goto error; |
702 | 595 | ||
703 | fid->qid = fcall->params.rstat.stat.qid; | ||
704 | v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb); | ||
705 | if((fid->qid.version)&&(v9ses->cache)) | 596 | if((fid->qid.version)&&(v9ses->cache)) |
706 | dentry->d_op = &v9fs_cached_dentry_operations; | 597 | dentry->d_op = &v9fs_cached_dentry_operations; |
707 | else | 598 | else |
708 | dentry->d_op = &v9fs_dentry_operations; | 599 | dentry->d_op = &v9fs_dentry_operations; |
709 | 600 | ||
710 | d_add(dentry, inode); | 601 | d_add(dentry, inode); |
711 | kfree(fcall); | ||
712 | |||
713 | return NULL; | 602 | return NULL; |
714 | 603 | ||
715 | Release_Dirfid: | 604 | error: |
716 | up(&dirfid->lock); | 605 | if (fid) |
717 | 606 | p9_client_clunk(fid); | |
718 | FreeFcall: | ||
719 | kfree(fcall); | ||
720 | 607 | ||
721 | return ERR_PTR(result); | 608 | return ERR_PTR(result); |
722 | } | 609 | } |
@@ -758,73 +645,54 @@ static int | |||
758 | v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | 645 | v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, |
759 | struct inode *new_dir, struct dentry *new_dentry) | 646 | struct inode *new_dir, struct dentry *new_dentry) |
760 | { | 647 | { |
761 | struct inode *old_inode = old_dentry->d_inode; | 648 | struct inode *old_inode; |
762 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode); | 649 | struct v9fs_session_info *v9ses; |
763 | struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); | 650 | struct p9_fid *oldfid; |
764 | struct v9fs_fid *olddirfid; | 651 | struct p9_fid *olddirfid; |
765 | struct v9fs_fid *newdirfid; | 652 | struct p9_fid *newdirfid; |
766 | struct v9fs_wstat wstat; | 653 | struct p9_wstat wstat; |
767 | struct v9fs_fcall *fcall = NULL; | 654 | int retval; |
768 | int fid = -1; | ||
769 | int olddirfidnum = -1; | ||
770 | int newdirfidnum = -1; | ||
771 | int retval = 0; | ||
772 | |||
773 | dprintk(DEBUG_VFS, "\n"); | ||
774 | 655 | ||
656 | P9_DPRINTK(P9_DEBUG_VFS, "\n"); | ||
657 | retval = 0; | ||
658 | old_inode = old_dentry->d_inode; | ||
659 | v9ses = v9fs_inode2v9ses(old_inode); | ||
660 | oldfid = v9fs_fid_lookup(old_dentry); | ||
775 | if(IS_ERR(oldfid)) | 661 | if(IS_ERR(oldfid)) |
776 | return PTR_ERR(oldfid); | 662 | return PTR_ERR(oldfid); |
777 | 663 | ||
778 | olddirfid = v9fs_fid_clone(old_dentry->d_parent); | 664 | olddirfid = v9fs_fid_clone(old_dentry->d_parent); |
779 | if(IS_ERR(olddirfid)) { | 665 | if(IS_ERR(olddirfid)) { |
780 | retval = PTR_ERR(olddirfid); | 666 | retval = PTR_ERR(olddirfid); |
781 | goto Release_lock; | 667 | goto done; |
782 | } | 668 | } |
783 | 669 | ||
784 | newdirfid = v9fs_fid_clone(new_dentry->d_parent); | 670 | newdirfid = v9fs_fid_clone(new_dentry->d_parent); |
785 | if(IS_ERR(newdirfid)) { | 671 | if(IS_ERR(newdirfid)) { |
786 | retval = PTR_ERR(newdirfid); | 672 | retval = PTR_ERR(newdirfid); |
787 | goto Clunk_olddir; | 673 | goto clunk_olddir; |
788 | } | 674 | } |
789 | 675 | ||
790 | /* 9P can only handle file rename in the same directory */ | 676 | /* 9P can only handle file rename in the same directory */ |
791 | if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) { | 677 | if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) { |
792 | dprintk(DEBUG_ERROR, "old dir and new dir are different\n"); | 678 | P9_DPRINTK(P9_DEBUG_ERROR, |
679 | "old dir and new dir are different\n"); | ||
793 | retval = -EXDEV; | 680 | retval = -EXDEV; |
794 | goto Clunk_newdir; | 681 | goto clunk_newdir; |
795 | } | ||
796 | |||
797 | fid = oldfid->fid; | ||
798 | olddirfidnum = olddirfid->fid; | ||
799 | newdirfidnum = newdirfid->fid; | ||
800 | |||
801 | if (fid < 0) { | ||
802 | dprintk(DEBUG_ERROR, "no fid for old file #%lu\n", | ||
803 | old_inode->i_ino); | ||
804 | retval = -EBADF; | ||
805 | goto Clunk_newdir; | ||
806 | } | 682 | } |
807 | 683 | ||
808 | v9fs_blank_wstat(&wstat); | 684 | v9fs_blank_wstat(&wstat); |
809 | wstat.muid = v9ses->name; | 685 | wstat.muid = v9ses->name; |
810 | wstat.name = (char *) new_dentry->d_name.name; | 686 | wstat.name = (char *) new_dentry->d_name.name; |
687 | retval = p9_client_wstat(oldfid, &wstat); | ||
811 | 688 | ||
812 | retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall); | 689 | clunk_newdir: |
690 | p9_client_clunk(olddirfid); | ||
813 | 691 | ||
814 | if (retval < 0) | 692 | clunk_olddir: |
815 | PRINT_FCALL_ERROR("wstat error", fcall); | 693 | p9_client_clunk(newdirfid); |
816 | |||
817 | kfree(fcall); | ||
818 | |||
819 | Clunk_newdir: | ||
820 | v9fs_fid_clunk(v9ses, newdirfid); | ||
821 | |||
822 | Clunk_olddir: | ||
823 | v9fs_fid_clunk(v9ses, olddirfid); | ||
824 | |||
825 | Release_lock: | ||
826 | up(&oldfid->lock); | ||
827 | 694 | ||
695 | done: | ||
828 | return retval; | 696 | return retval; |
829 | } | 697 | } |
830 | 698 | ||
@@ -840,28 +708,27 @@ static int | |||
840 | v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | 708 | v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, |
841 | struct kstat *stat) | 709 | struct kstat *stat) |
842 | { | 710 | { |
843 | struct v9fs_fcall *fcall = NULL; | 711 | int err; |
844 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 712 | struct v9fs_session_info *v9ses; |
845 | struct v9fs_fid *fid = v9fs_fid_clone(dentry); | 713 | struct p9_fid *fid; |
846 | int err = -EPERM; | 714 | struct p9_stat *st; |
847 | 715 | ||
848 | dprintk(DEBUG_VFS, "dentry: %p\n", dentry); | 716 | P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); |
849 | if(IS_ERR(fid)) | 717 | err = -EPERM; |
718 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | ||
719 | fid = v9fs_fid_lookup(dentry); | ||
720 | if (IS_ERR(fid)) | ||
850 | return PTR_ERR(fid); | 721 | return PTR_ERR(fid); |
851 | 722 | ||
852 | err = v9fs_t_stat(v9ses, fid->fid, &fcall); | 723 | st = p9_client_stat(fid); |
724 | if (IS_ERR(st)) | ||
725 | return PTR_ERR(st); | ||
853 | 726 | ||
854 | if (err < 0) | 727 | v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb); |
855 | dprintk(DEBUG_ERROR, "stat error\n"); | ||
856 | else { | ||
857 | v9fs_stat2inode(&fcall->params.rstat.stat, dentry->d_inode, | ||
858 | dentry->d_inode->i_sb); | ||
859 | generic_fillattr(dentry->d_inode, stat); | 728 | generic_fillattr(dentry->d_inode, stat); |
860 | } | ||
861 | 729 | ||
862 | kfree(fcall); | 730 | kfree(st); |
863 | v9fs_fid_clunk(v9ses, fid); | 731 | return 0; |
864 | return err; | ||
865 | } | 732 | } |
866 | 733 | ||
867 | /** | 734 | /** |
@@ -873,13 +740,15 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
873 | 740 | ||
874 | static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) | 741 | static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) |
875 | { | 742 | { |
876 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 743 | int retval; |
877 | struct v9fs_fid *fid = v9fs_fid_clone(dentry); | 744 | struct v9fs_session_info *v9ses; |
878 | struct v9fs_fcall *fcall = NULL; | 745 | struct p9_fid *fid; |
879 | struct v9fs_wstat wstat; | 746 | struct p9_wstat wstat; |
880 | int res = -EPERM; | ||
881 | 747 | ||
882 | dprintk(DEBUG_VFS, "\n"); | 748 | P9_DPRINTK(P9_DEBUG_VFS, "\n"); |
749 | retval = -EPERM; | ||
750 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | ||
751 | fid = v9fs_fid_lookup(dentry); | ||
883 | if(IS_ERR(fid)) | 752 | if(IS_ERR(fid)) |
884 | return PTR_ERR(fid); | 753 | return PTR_ERR(fid); |
885 | 754 | ||
@@ -904,17 +773,11 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
904 | wstat.n_gid = iattr->ia_gid; | 773 | wstat.n_gid = iattr->ia_gid; |
905 | } | 774 | } |
906 | 775 | ||
907 | res = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall); | 776 | retval = p9_client_wstat(fid, &wstat); |
777 | if (retval >= 0) | ||
778 | retval = inode_setattr(dentry->d_inode, iattr); | ||
908 | 779 | ||
909 | if (res < 0) | 780 | return retval; |
910 | PRINT_FCALL_ERROR("wstat error", fcall); | ||
911 | |||
912 | kfree(fcall); | ||
913 | if (res >= 0) | ||
914 | res = inode_setattr(dentry->d_inode, iattr); | ||
915 | |||
916 | v9fs_fid_clunk(v9ses, fid); | ||
917 | return res; | ||
918 | } | 781 | } |
919 | 782 | ||
920 | /** | 783 | /** |
@@ -926,7 +789,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
926 | */ | 789 | */ |
927 | 790 | ||
928 | void | 791 | void |
929 | v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode, | 792 | v9fs_stat2inode(struct p9_stat *stat, struct inode *inode, |
930 | struct super_block *sb) | 793 | struct super_block *sb) |
931 | { | 794 | { |
932 | int n; | 795 | int n; |
@@ -967,8 +830,9 @@ v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode, | |||
967 | case 'b': | 830 | case 'b': |
968 | break; | 831 | break; |
969 | default: | 832 | default: |
970 | dprintk(DEBUG_ERROR, "Unknown special type %c (%.*s)\n", | 833 | P9_DPRINTK(P9_DEBUG_ERROR, |
971 | type, stat->extension.len, stat->extension.str); | 834 | "Unknown special type %c (%.*s)\n", type, |
835 | stat->extension.len, stat->extension.str); | ||
972 | }; | 836 | }; |
973 | inode->i_rdev = MKDEV(major, minor); | 837 | inode->i_rdev = MKDEV(major, minor); |
974 | } else | 838 | } else |
@@ -976,8 +840,8 @@ v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode, | |||
976 | 840 | ||
977 | inode->i_size = stat->length; | 841 | inode->i_size = stat->length; |
978 | 842 | ||
979 | inode->i_blocks = | 843 | /* not real number of blocks, but 512 byte ones ... */ |
980 | (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; | 844 | inode->i_blocks = (inode->i_size + 512 - 1) >> 9; |
981 | } | 845 | } |
982 | 846 | ||
983 | /** | 847 | /** |
@@ -987,7 +851,7 @@ v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode, | |||
987 | * BUG: potential for inode number collisions? | 851 | * BUG: potential for inode number collisions? |
988 | */ | 852 | */ |
989 | 853 | ||
990 | ino_t v9fs_qid2ino(struct v9fs_qid *qid) | 854 | ino_t v9fs_qid2ino(struct p9_qid *qid) |
991 | { | 855 | { |
992 | u64 path = qid->path + 2; | 856 | u64 path = qid->path + 2; |
993 | ino_t i = 0; | 857 | ino_t i = 0; |
@@ -1010,56 +874,46 @@ ino_t v9fs_qid2ino(struct v9fs_qid *qid) | |||
1010 | 874 | ||
1011 | static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) | 875 | static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) |
1012 | { | 876 | { |
1013 | int retval = -EPERM; | 877 | int retval; |
1014 | 878 | ||
1015 | struct v9fs_fcall *fcall = NULL; | 879 | struct v9fs_session_info *v9ses; |
1016 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 880 | struct p9_fid *fid; |
1017 | struct v9fs_fid *fid = v9fs_fid_clone(dentry); | 881 | struct p9_stat *st; |
1018 | 882 | ||
883 | P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name); | ||
884 | retval = -EPERM; | ||
885 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | ||
886 | fid = v9fs_fid_lookup(dentry); | ||
1019 | if(IS_ERR(fid)) | 887 | if(IS_ERR(fid)) |
1020 | return PTR_ERR(fid); | 888 | return PTR_ERR(fid); |
1021 | 889 | ||
1022 | if (!v9ses->extended) { | 890 | if (!v9ses->extended) |
1023 | retval = -EBADF; | 891 | return -EBADF; |
1024 | dprintk(DEBUG_ERROR, "not extended\n"); | ||
1025 | goto ClunkFid; | ||
1026 | } | ||
1027 | |||
1028 | dprintk(DEBUG_VFS, " %s\n", dentry->d_name.name); | ||
1029 | retval = v9fs_t_stat(v9ses, fid->fid, &fcall); | ||
1030 | |||
1031 | if (retval < 0) { | ||
1032 | dprintk(DEBUG_ERROR, "stat error\n"); | ||
1033 | goto FreeFcall; | ||
1034 | } | ||
1035 | 892 | ||
1036 | if (!fcall) { | 893 | st = p9_client_stat(fid); |
1037 | retval = -EIO; | 894 | if (IS_ERR(st)) |
1038 | goto ClunkFid; | 895 | return PTR_ERR(st); |
1039 | } | ||
1040 | 896 | ||
1041 | if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) { | 897 | if (!(st->mode & P9_DMSYMLINK)) { |
1042 | retval = -EINVAL; | 898 | retval = -EINVAL; |
1043 | goto FreeFcall; | 899 | goto done; |
1044 | } | 900 | } |
1045 | 901 | ||
1046 | /* copy extension buffer into buffer */ | 902 | /* copy extension buffer into buffer */ |
1047 | if (fcall->params.rstat.stat.extension.len < buflen) | 903 | if (st->extension.len < buflen) |
1048 | buflen = fcall->params.rstat.stat.extension.len + 1; | 904 | buflen = st->extension.len + 1; |
1049 | 905 | ||
1050 | memmove(buffer, fcall->params.rstat.stat.extension.str, buflen - 1); | 906 | memmove(buffer, st->extension.str, buflen - 1); |
1051 | buffer[buflen-1] = 0; | 907 | buffer[buflen-1] = 0; |
1052 | 908 | ||
1053 | dprintk(DEBUG_ERROR, "%s -> %.*s (%s)\n", dentry->d_name.name, fcall->params.rstat.stat.extension.len, | 909 | P9_DPRINTK(P9_DEBUG_VFS, |
1054 | fcall->params.rstat.stat.extension.str, buffer); | 910 | "%s -> %.*s (%s)\n", dentry->d_name.name, st->extension.len, |
1055 | retval = buflen; | 911 | st->extension.str, buffer); |
1056 | 912 | ||
1057 | FreeFcall: | 913 | retval = buflen; |
1058 | kfree(fcall); | ||
1059 | |||
1060 | ClunkFid: | ||
1061 | v9fs_fid_clunk(v9ses, fid); | ||
1062 | 914 | ||
915 | done: | ||
916 | kfree(st); | ||
1063 | return retval; | 917 | return retval; |
1064 | } | 918 | } |
1065 | 919 | ||
@@ -1084,14 +938,14 @@ static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer, | |||
1084 | if (buflen > PATH_MAX) | 938 | if (buflen > PATH_MAX) |
1085 | buflen = PATH_MAX; | 939 | buflen = PATH_MAX; |
1086 | 940 | ||
1087 | dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); | 941 | P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); |
1088 | 942 | ||
1089 | retval = v9fs_readlink(dentry, link, buflen); | 943 | retval = v9fs_readlink(dentry, link, buflen); |
1090 | 944 | ||
1091 | if (retval > 0) { | 945 | if (retval > 0) { |
1092 | if ((ret = copy_to_user(buffer, link, retval)) != 0) { | 946 | if ((ret = copy_to_user(buffer, link, retval)) != 0) { |
1093 | dprintk(DEBUG_ERROR, "problem copying to user: %d\n", | 947 | P9_DPRINTK(P9_DEBUG_ERROR, |
1094 | ret); | 948 | "problem copying to user: %d\n", ret); |
1095 | retval = ret; | 949 | retval = ret; |
1096 | } | 950 | } |
1097 | } | 951 | } |
@@ -1112,7 +966,7 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
1112 | int len = 0; | 966 | int len = 0; |
1113 | char *link = __getname(); | 967 | char *link = __getname(); |
1114 | 968 | ||
1115 | dprintk(DEBUG_VFS, "%s n", dentry->d_name.name); | 969 | P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name); |
1116 | 970 | ||
1117 | if (!link) | 971 | if (!link) |
1118 | link = ERR_PTR(-ENOMEM); | 972 | link = ERR_PTR(-ENOMEM); |
@@ -1141,7 +995,7 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void | |||
1141 | { | 995 | { |
1142 | char *s = nd_get_link(nd); | 996 | char *s = nd_get_link(nd); |
1143 | 997 | ||
1144 | dprintk(DEBUG_VFS, " %s %s\n", dentry->d_name.name, s); | 998 | P9_DPRINTK(P9_DEBUG_VFS, " %s %s\n", dentry->d_name.name, s); |
1145 | if (!IS_ERR(s)) | 999 | if (!IS_ERR(s)) |
1146 | __putname(s); | 1000 | __putname(s); |
1147 | } | 1001 | } |
@@ -1149,66 +1003,24 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void | |||
1149 | static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, | 1003 | static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, |
1150 | int mode, const char *extension) | 1004 | int mode, const char *extension) |
1151 | { | 1005 | { |
1152 | int err; | 1006 | u32 perm; |
1153 | u32 fid, perm; | ||
1154 | struct v9fs_session_info *v9ses; | 1007 | struct v9fs_session_info *v9ses; |
1155 | struct v9fs_fid *dfid, *vfid = NULL; | 1008 | struct p9_fid *fid; |
1156 | struct inode *inode = NULL; | ||
1157 | 1009 | ||
1158 | v9ses = v9fs_inode2v9ses(dir); | 1010 | v9ses = v9fs_inode2v9ses(dir); |
1159 | if (!v9ses->extended) { | 1011 | if (!v9ses->extended) { |
1160 | dprintk(DEBUG_ERROR, "not extended\n"); | 1012 | P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n"); |
1161 | return -EPERM; | 1013 | return -EPERM; |
1162 | } | 1014 | } |
1163 | 1015 | ||
1164 | dfid = v9fs_fid_clone(dentry->d_parent); | ||
1165 | if(IS_ERR(dfid)) { | ||
1166 | err = PTR_ERR(dfid); | ||
1167 | goto error; | ||
1168 | } | ||
1169 | |||
1170 | perm = unixmode2p9mode(v9ses, mode); | 1016 | perm = unixmode2p9mode(v9ses, mode); |
1017 | fid = v9fs_create(v9ses, dir, dentry, (char *) extension, perm, | ||
1018 | P9_OREAD); | ||
1019 | if (IS_ERR(fid)) | ||
1020 | return PTR_ERR(fid); | ||
1171 | 1021 | ||
1172 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, | 1022 | p9_client_clunk(fid); |
1173 | perm, V9FS_OREAD, (char *) extension, &fid, NULL, NULL); | ||
1174 | |||
1175 | if (err) | ||
1176 | goto clunk_dfid; | ||
1177 | |||
1178 | err = v9fs_t_clunk(v9ses, fid); | ||
1179 | if (err) | ||
1180 | goto clunk_dfid; | ||
1181 | |||
1182 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); | ||
1183 | if (IS_ERR(vfid)) { | ||
1184 | err = PTR_ERR(vfid); | ||
1185 | vfid = NULL; | ||
1186 | goto clunk_dfid; | ||
1187 | } | ||
1188 | |||
1189 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); | ||
1190 | if (IS_ERR(inode)) { | ||
1191 | err = PTR_ERR(inode); | ||
1192 | inode = NULL; | ||
1193 | goto free_vfid; | ||
1194 | } | ||
1195 | |||
1196 | if(v9ses->cache) | ||
1197 | dentry->d_op = &v9fs_cached_dentry_operations; | ||
1198 | else | ||
1199 | dentry->d_op = &v9fs_dentry_operations; | ||
1200 | d_instantiate(dentry, inode); | ||
1201 | return 0; | 1023 | return 0; |
1202 | |||
1203 | free_vfid: | ||
1204 | v9fs_fid_destroy(vfid); | ||
1205 | |||
1206 | clunk_dfid: | ||
1207 | v9fs_fid_clunk(v9ses, dfid); | ||
1208 | |||
1209 | error: | ||
1210 | return err; | ||
1211 | |||
1212 | } | 1024 | } |
1213 | 1025 | ||
1214 | /** | 1026 | /** |
@@ -1224,8 +1036,8 @@ error: | |||
1224 | static int | 1036 | static int |
1225 | v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | 1037 | v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) |
1226 | { | 1038 | { |
1227 | dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, | 1039 | P9_DPRINTK(P9_DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, |
1228 | symname); | 1040 | dentry->d_name.name, symname); |
1229 | 1041 | ||
1230 | return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname); | 1042 | return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname); |
1231 | } | 1043 | } |
@@ -1247,11 +1059,11 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, | |||
1247 | struct dentry *dentry) | 1059 | struct dentry *dentry) |
1248 | { | 1060 | { |
1249 | int retval; | 1061 | int retval; |
1250 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); | 1062 | struct p9_fid *oldfid; |
1251 | struct v9fs_fid *oldfid; | ||
1252 | char *name; | 1063 | char *name; |
1253 | 1064 | ||
1254 | dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, | 1065 | P9_DPRINTK(P9_DEBUG_VFS, |
1066 | " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, | ||
1255 | old_dentry->d_name.name); | 1067 | old_dentry->d_name.name); |
1256 | 1068 | ||
1257 | oldfid = v9fs_fid_clone(old_dentry); | 1069 | oldfid = v9fs_fid_clone(old_dentry); |
@@ -1265,11 +1077,11 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, | |||
1265 | } | 1077 | } |
1266 | 1078 | ||
1267 | sprintf(name, "%d\n", oldfid->fid); | 1079 | sprintf(name, "%d\n", oldfid->fid); |
1268 | retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name); | 1080 | retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name); |
1269 | __putname(name); | 1081 | __putname(name); |
1270 | 1082 | ||
1271 | clunk_fid: | 1083 | clunk_fid: |
1272 | v9fs_fid_clunk(v9ses, oldfid); | 1084 | p9_client_clunk(oldfid); |
1273 | return retval; | 1085 | return retval; |
1274 | } | 1086 | } |
1275 | 1087 | ||
@@ -1288,7 +1100,8 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | |||
1288 | int retval; | 1100 | int retval; |
1289 | char *name; | 1101 | char *name; |
1290 | 1102 | ||
1291 | dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, | 1103 | P9_DPRINTK(P9_DEBUG_VFS, |
1104 | " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, | ||
1292 | dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); | 1105 | dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); |
1293 | 1106 | ||
1294 | if (!new_valid_dev(rdev)) | 1107 | if (!new_valid_dev(rdev)) |
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 7bdf8b326841..f6a0519ade8c 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c | |||
@@ -37,10 +37,10 @@ | |||
37 | #include <linux/mount.h> | 37 | #include <linux/mount.h> |
38 | #include <linux/idr.h> | 38 | #include <linux/idr.h> |
39 | #include <linux/sched.h> | 39 | #include <linux/sched.h> |
40 | #include <net/9p/9p.h> | ||
41 | #include <net/9p/client.h> | ||
40 | 42 | ||
41 | #include "debug.h" | ||
42 | #include "v9fs.h" | 43 | #include "v9fs.h" |
43 | #include "9p.h" | ||
44 | #include "v9fs_vfs.h" | 44 | #include "v9fs_vfs.h" |
45 | #include "fid.h" | 45 | #include "fid.h" |
46 | 46 | ||
@@ -107,41 +107,48 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, | |||
107 | struct vfsmount *mnt) | 107 | struct vfsmount *mnt) |
108 | { | 108 | { |
109 | struct super_block *sb = NULL; | 109 | struct super_block *sb = NULL; |
110 | struct v9fs_fcall *fcall = NULL; | ||
111 | struct inode *inode = NULL; | 110 | struct inode *inode = NULL; |
112 | struct dentry *root = NULL; | 111 | struct dentry *root = NULL; |
113 | struct v9fs_session_info *v9ses = NULL; | 112 | struct v9fs_session_info *v9ses = NULL; |
114 | struct v9fs_fid *root_fid = NULL; | 113 | struct p9_stat *st = NULL; |
115 | int mode = S_IRWXUGO | S_ISVTX; | 114 | int mode = S_IRWXUGO | S_ISVTX; |
116 | uid_t uid = current->fsuid; | 115 | uid_t uid = current->fsuid; |
117 | gid_t gid = current->fsgid; | 116 | gid_t gid = current->fsgid; |
118 | int stat_result = 0; | 117 | struct p9_fid *fid; |
119 | int newfid = 0; | ||
120 | int retval = 0; | 118 | int retval = 0; |
121 | 119 | ||
122 | dprintk(DEBUG_VFS, " \n"); | 120 | P9_DPRINTK(P9_DEBUG_VFS, " \n"); |
123 | 121 | ||
124 | v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL); | 122 | v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL); |
125 | if (!v9ses) | 123 | if (!v9ses) |
126 | return -ENOMEM; | 124 | return -ENOMEM; |
127 | 125 | ||
128 | if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) { | 126 | fid = v9fs_session_init(v9ses, dev_name, data); |
129 | dprintk(DEBUG_ERROR, "problem initiating session\n"); | 127 | if (IS_ERR(fid)) { |
130 | retval = newfid; | 128 | retval = PTR_ERR(fid); |
131 | goto out_free_session; | 129 | fid = NULL; |
130 | kfree(v9ses); | ||
131 | v9ses = NULL; | ||
132 | goto error; | ||
133 | } | ||
134 | |||
135 | st = p9_client_stat(fid); | ||
136 | if (IS_ERR(st)) { | ||
137 | retval = PTR_ERR(st); | ||
138 | goto error; | ||
132 | } | 139 | } |
133 | 140 | ||
134 | sb = sget(fs_type, NULL, v9fs_set_super, v9ses); | 141 | sb = sget(fs_type, NULL, v9fs_set_super, v9ses); |
135 | if (IS_ERR(sb)) { | 142 | if (IS_ERR(sb)) { |
136 | retval = PTR_ERR(sb); | 143 | retval = PTR_ERR(sb); |
137 | goto out_close_session; | 144 | goto error; |
138 | } | 145 | } |
139 | v9fs_fill_super(sb, v9ses, flags); | 146 | v9fs_fill_super(sb, v9ses, flags); |
140 | 147 | ||
141 | inode = v9fs_get_inode(sb, S_IFDIR | mode); | 148 | inode = v9fs_get_inode(sb, S_IFDIR | mode); |
142 | if (IS_ERR(inode)) { | 149 | if (IS_ERR(inode)) { |
143 | retval = PTR_ERR(inode); | 150 | retval = PTR_ERR(inode); |
144 | goto put_back_sb; | 151 | goto error; |
145 | } | 152 | } |
146 | 153 | ||
147 | inode->i_uid = uid; | 154 | inode->i_uid = uid; |
@@ -150,54 +157,30 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, | |||
150 | root = d_alloc_root(inode); | 157 | root = d_alloc_root(inode); |
151 | if (!root) { | 158 | if (!root) { |
152 | retval = -ENOMEM; | 159 | retval = -ENOMEM; |
153 | goto put_back_sb; | 160 | goto error; |
154 | } | 161 | } |
155 | 162 | ||
156 | sb->s_root = root; | 163 | sb->s_root = root; |
164 | root->d_inode->i_ino = v9fs_qid2ino(&st->qid); | ||
165 | v9fs_stat2inode(st, root->d_inode, sb); | ||
166 | v9fs_fid_add(root, fid); | ||
157 | 167 | ||
158 | stat_result = v9fs_t_stat(v9ses, newfid, &fcall); | 168 | return simple_set_mnt(mnt, sb); |
159 | if (stat_result < 0) { | ||
160 | dprintk(DEBUG_ERROR, "stat error\n"); | ||
161 | v9fs_t_clunk(v9ses, newfid); | ||
162 | } else { | ||
163 | /* Setup the Root Inode */ | ||
164 | root_fid = v9fs_fid_create(v9ses, newfid); | ||
165 | if (root_fid == NULL) { | ||
166 | retval = -ENOMEM; | ||
167 | goto put_back_sb; | ||
168 | } | ||
169 | |||
170 | retval = v9fs_fid_insert(root_fid, root); | ||
171 | if (retval < 0) { | ||
172 | kfree(fcall); | ||
173 | goto put_back_sb; | ||
174 | } | ||
175 | |||
176 | root_fid->qid = fcall->params.rstat.stat.qid; | ||
177 | root->d_inode->i_ino = | ||
178 | v9fs_qid2ino(&fcall->params.rstat.stat.qid); | ||
179 | v9fs_stat2inode(&fcall->params.rstat.stat, root->d_inode, sb); | ||
180 | } | ||
181 | 169 | ||
182 | kfree(fcall); | 170 | error: |
171 | if (fid) | ||
172 | p9_client_clunk(fid); | ||
183 | 173 | ||
184 | if (stat_result < 0) { | 174 | if (v9ses) { |
185 | retval = stat_result; | 175 | v9fs_session_close(v9ses); |
186 | goto put_back_sb; | 176 | kfree(v9ses); |
187 | } | 177 | } |
188 | 178 | ||
189 | return simple_set_mnt(mnt, sb); | 179 | if (sb) { |
190 | 180 | up_write(&sb->s_umount); | |
191 | out_close_session: | 181 | deactivate_super(sb); |
192 | v9fs_session_close(v9ses); | 182 | } |
193 | out_free_session: | ||
194 | kfree(v9ses); | ||
195 | return retval; | ||
196 | 183 | ||
197 | put_back_sb: | ||
198 | /* deactivate_super calls v9fs_kill_super which will frees the rest */ | ||
199 | up_write(&sb->s_umount); | ||
200 | deactivate_super(sb); | ||
201 | return retval; | 184 | return retval; |
202 | } | 185 | } |
203 | 186 | ||
@@ -211,7 +194,7 @@ static void v9fs_kill_super(struct super_block *s) | |||
211 | { | 194 | { |
212 | struct v9fs_session_info *v9ses = s->s_fs_info; | 195 | struct v9fs_session_info *v9ses = s->s_fs_info; |
213 | 196 | ||
214 | dprintk(DEBUG_VFS, " %p\n", s); | 197 | P9_DPRINTK(P9_DEBUG_VFS, " %p\n", s); |
215 | 198 | ||
216 | v9fs_dentry_release(s->s_root); /* clunk root */ | 199 | v9fs_dentry_release(s->s_root); /* clunk root */ |
217 | 200 | ||
@@ -219,7 +202,7 @@ static void v9fs_kill_super(struct super_block *s) | |||
219 | 202 | ||
220 | v9fs_session_close(v9ses); | 203 | v9fs_session_close(v9ses); |
221 | kfree(v9ses); | 204 | kfree(v9ses); |
222 | dprintk(DEBUG_VFS, "exiting kill_super\n"); | 205 | P9_DPRINTK(P9_DEBUG_VFS, "exiting kill_super\n"); |
223 | } | 206 | } |
224 | 207 | ||
225 | /** | 208 | /** |