[PATCH] v9fs: print 9p messages
[safe/jmp/linux-2.6] / fs / 9p / trans_fd.c
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  *  Copyright (C) 1995, 1996 by Olaf Kirch <okir@monad.swb.de>
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
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/config.h>
31 #include <linux/in.h>
32 #include <linux/module.h>
33 #include <linux/net.h>
34 #include <linux/ipv6.h>
35 #include <linux/errno.h>
36 #include <linux/kernel.h>
37 #include <linux/un.h>
38 #include <asm/uaccess.h>
39 #include <linux/inet.h>
40 #include <linux/idr.h>
41 #include <linux/file.h>
42
43 #include "debug.h"
44 #include "v9fs.h"
45 #include "transport.h"
46
47 #define V9FS_PORT 564
48
49 struct v9fs_trans_fd {
50         struct file *rd;
51         struct file *wr;
52 };
53
54 /**
55  * v9fs_fd_read- read from a fd
56  * @v9ses: session information
57  * @v: buffer to receive data into
58  * @len: size of receive buffer
59  *
60  */
61 static int v9fs_fd_read(struct v9fs_transport *trans, void *v, int len)
62 {
63         int ret;
64         struct v9fs_trans_fd *ts;
65
66         if (!trans || trans->status == Disconnected || !(ts = trans->priv))
67                 return -EREMOTEIO;
68
69         if (!(ts->rd->f_flags & O_NONBLOCK))
70                 dprintk(DEBUG_ERROR, "blocking read ...\n");
71
72         ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
73         if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
74                 trans->status = Disconnected;
75         return ret;
76 }
77
78 /**
79  * v9fs_fd_write - write to a socket
80  * @v9ses: session information
81  * @v: buffer to send data from
82  * @len: size of send buffer
83  *
84  */
85 static int v9fs_fd_write(struct v9fs_transport *trans, void *v, int len)
86 {
87         int ret;
88         mm_segment_t oldfs;
89         struct v9fs_trans_fd *ts;
90
91         if (!trans || trans->status == Disconnected || !(ts = trans->priv))
92                 return -EREMOTEIO;
93
94         if (!(ts->wr->f_flags & O_NONBLOCK))
95                 dprintk(DEBUG_ERROR, "blocking write ...\n");
96
97         oldfs = get_fs();
98         set_fs(get_ds());
99         /* The cast to a user pointer is valid due to the set_fs() */
100         ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
101         set_fs(oldfs);
102
103         if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
104                 trans->status = Disconnected;
105         return ret;
106 }
107
108 static unsigned int
109 v9fs_fd_poll(struct v9fs_transport *trans, struct poll_table_struct *pt)
110 {
111         int ret, n;
112         struct v9fs_trans_fd *ts;
113         mm_segment_t oldfs;
114
115         if (!trans || trans->status != Connected || !(ts = trans->priv))
116                 return -EREMOTEIO;
117
118         if (!ts->rd->f_op || !ts->rd->f_op->poll)
119                 return -EIO;
120
121         if (!ts->wr->f_op || !ts->wr->f_op->poll)
122                 return -EIO;
123
124         oldfs = get_fs();
125         set_fs(get_ds());
126
127         ret = ts->rd->f_op->poll(ts->rd, pt);
128         if (ret < 0)
129                 goto end;
130
131         if (ts->rd != ts->wr) {
132                 n = ts->wr->f_op->poll(ts->wr, pt);
133                 if (n < 0) {
134                         ret = n;
135                         goto end;
136                 }
137                 ret = (ret & ~POLLOUT) | (n & ~POLLIN);
138         }
139
140       end:
141         set_fs(oldfs);
142         return ret;
143 }
144
145 static int v9fs_fd_open(struct v9fs_session_info *v9ses, int rfd, int wfd)
146 {
147         struct v9fs_transport *trans = v9ses->transport;
148         struct v9fs_trans_fd *ts = kmalloc(sizeof(struct v9fs_trans_fd),
149                                            GFP_KERNEL);
150         if (!ts)
151                 return -ENOMEM;
152
153         ts->rd = fget(rfd);
154         ts->wr = fget(wfd);
155         if (!ts->rd || !ts->wr) {
156                 if (ts->rd)
157                         fput(ts->rd);
158                 if (ts->wr)
159                         fput(ts->wr);
160                 kfree(ts);
161                 return -EIO;
162         }
163
164         trans->priv = ts;
165         trans->status = Connected;
166
167         return 0;
168 }
169
170 static int v9fs_fd_init(struct v9fs_session_info *v9ses, const char *addr,
171                         char *data)
172 {
173         if (v9ses->rfdno == ~0 || v9ses->wfdno == ~0) {
174                 printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
175                 return -ENOPROTOOPT;
176         }
177
178         return v9fs_fd_open(v9ses, v9ses->rfdno, v9ses->wfdno);
179 }
180
181 static int v9fs_socket_open(struct v9fs_session_info *v9ses,
182                             struct socket *csocket)
183 {
184         int fd, ret;
185
186         csocket->sk->sk_allocation = GFP_NOIO;
187         if ((fd = sock_map_fd(csocket)) < 0) {
188                 eprintk(KERN_ERR, "v9fs_socket_open: failed to map fd\n");
189                 ret = fd;
190               release_csocket:
191                 sock_release(csocket);
192                 return ret;
193         }
194
195         if ((ret = v9fs_fd_open(v9ses, fd, fd)) < 0) {
196                 sockfd_put(csocket);
197                 eprintk(KERN_ERR, "v9fs_socket_open: failed to open fd\n");
198                 goto release_csocket;
199         }
200
201         ((struct v9fs_trans_fd *)v9ses->transport->priv)->rd->f_flags |=
202             O_NONBLOCK;
203         return 0;
204 }
205
206 static int v9fs_tcp_init(struct v9fs_session_info *v9ses, const char *addr,
207                          char *data)
208 {
209         int ret;
210         struct socket *csocket = NULL;
211         struct sockaddr_in sin_server;
212
213         sin_server.sin_family = AF_INET;
214         sin_server.sin_addr.s_addr = in_aton(addr);
215         sin_server.sin_port = htons(v9ses->port);
216         sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
217
218         if (!csocket) {
219                 eprintk(KERN_ERR, "v9fs_trans_tcp: problem creating socket\n");
220                 return -1;
221         }
222
223         ret = csocket->ops->connect(csocket,
224                                     (struct sockaddr *)&sin_server,
225                                     sizeof(struct sockaddr_in), 0);
226         if (ret < 0) {
227                 eprintk(KERN_ERR,
228                         "v9fs_trans_tcp: problem connecting socket to %s\n",
229                         addr);
230                 return ret;
231         }
232
233         return v9fs_socket_open(v9ses, csocket);
234 }
235
236 static int
237 v9fs_unix_init(struct v9fs_session_info *v9ses, const char *addr, char *data)
238 {
239         int ret;
240         struct socket *csocket;
241         struct sockaddr_un sun_server;
242
243         if (strlen(addr) > UNIX_PATH_MAX) {
244                 eprintk(KERN_ERR, "v9fs_trans_unix: address too long: %s\n",
245                         addr);
246                 return -ENAMETOOLONG;
247         }
248
249         sun_server.sun_family = PF_UNIX;
250         strcpy(sun_server.sun_path, addr);
251         sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
252         ret = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
253                         sizeof(struct sockaddr_un) - 1, 0);
254         if (ret < 0) {
255                 eprintk(KERN_ERR,
256                         "v9fs_trans_unix: problem connecting socket: %s: %d\n",
257                         addr, ret);
258                 return ret;
259         }
260
261         return v9fs_socket_open(v9ses, csocket);
262 }
263
264 /**
265  * v9fs_sock_close - shutdown socket
266  * @trans: private socket structure
267  *
268  */
269 static void v9fs_fd_close(struct v9fs_transport *trans)
270 {
271         struct v9fs_trans_fd *ts;
272
273         if (!trans)
274                 return;
275
276         ts = xchg(&trans->priv, NULL);
277
278         if (!ts)
279                 return;
280
281         trans->status = Disconnected;
282         if (ts->rd)
283                 fput(ts->rd);
284         if (ts->wr)
285                 fput(ts->wr);
286         kfree(ts);
287 }
288
289 struct v9fs_transport v9fs_trans_fd = {
290         .init = v9fs_fd_init,
291         .write = v9fs_fd_write,
292         .read = v9fs_fd_read,
293         .close = v9fs_fd_close,
294         .poll = v9fs_fd_poll,
295 };
296
297 struct v9fs_transport v9fs_trans_tcp = {
298         .init = v9fs_tcp_init,
299         .write = v9fs_fd_write,
300         .read = v9fs_fd_read,
301         .close = v9fs_fd_close,
302         .poll = v9fs_fd_poll,
303 };
304
305 struct v9fs_transport v9fs_trans_unix = {
306         .init = v9fs_unix_init,
307         .write = v9fs_fd_write,
308         .read = v9fs_fd_read,
309         .close = v9fs_fd_close,
310         .poll = v9fs_fd_poll,
311 };