2 * linux/fs/9p/trans_fd.c
4 * Fd transport layer. Includes deprecated socket layer.
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>
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.
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.
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
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>
35 #include <linux/uaccess.h>
36 #include <linux/inet.h>
37 #include <linux/idr.h>
38 #include <linux/file.h>
39 #include <net/9p/9p.h>
40 #include <net/9p/transport.h>
49 static int p9_socket_open(struct p9_transport
*trans
, struct socket
*csocket
);
50 static int p9_fd_open(struct p9_transport
*trans
, int rfd
, int wfd
);
51 static int p9_fd_read(struct p9_transport
*trans
, void *v
, int len
);
52 static int p9_fd_write(struct p9_transport
*trans
, void *v
, int len
);
53 static unsigned int p9_fd_poll(struct p9_transport
*trans
,
54 struct poll_table_struct
*pt
);
55 static void p9_fd_close(struct p9_transport
*trans
);
57 struct p9_transport
*p9_trans_create_tcp(const char *addr
, int port
)
60 struct p9_transport
*trans
;
61 struct socket
*csocket
;
62 struct sockaddr_in sin_server
;
65 trans
= kmalloc(sizeof(struct p9_transport
), GFP_KERNEL
);
67 return ERR_PTR(-ENOMEM
);
69 trans
->write
= p9_fd_write
;
70 trans
->read
= p9_fd_read
;
71 trans
->close
= p9_fd_close
;
72 trans
->poll
= p9_fd_poll
;
74 sin_server
.sin_family
= AF_INET
;
75 sin_server
.sin_addr
.s_addr
= in_aton(addr
);
76 sin_server
.sin_port
= htons(port
);
77 sock_create_kern(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
, &csocket
);
80 P9_EPRINTK(KERN_ERR
, "p9_trans_tcp: problem creating socket\n");
85 err
= csocket
->ops
->connect(csocket
,
86 (struct sockaddr
*)&sin_server
,
87 sizeof(struct sockaddr_in
), 0);
90 "p9_trans_tcp: problem connecting socket to %s\n",
95 err
= p9_socket_open(trans
, csocket
);
103 sock_release(csocket
);
108 EXPORT_SYMBOL(p9_trans_create_tcp
);
110 struct p9_transport
*p9_trans_create_unix(const char *addr
)
113 struct socket
*csocket
;
114 struct sockaddr_un sun_server
;
115 struct p9_transport
*trans
;
118 trans
= kmalloc(sizeof(struct p9_transport
), GFP_KERNEL
);
120 return ERR_PTR(-ENOMEM
);
122 trans
->write
= p9_fd_write
;
123 trans
->read
= p9_fd_read
;
124 trans
->close
= p9_fd_close
;
125 trans
->poll
= p9_fd_poll
;
127 if (strlen(addr
) > UNIX_PATH_MAX
) {
128 P9_EPRINTK(KERN_ERR
, "p9_trans_unix: address too long: %s\n",
134 sun_server
.sun_family
= PF_UNIX
;
135 strcpy(sun_server
.sun_path
, addr
);
136 sock_create_kern(PF_UNIX
, SOCK_STREAM
, 0, &csocket
);
137 err
= csocket
->ops
->connect(csocket
, (struct sockaddr
*)&sun_server
,
138 sizeof(struct sockaddr_un
) - 1, 0);
141 "p9_trans_unix: problem connecting socket: %s: %d\n",
146 err
= p9_socket_open(trans
, csocket
);
154 sock_release(csocket
);
159 EXPORT_SYMBOL(p9_trans_create_unix
);
161 struct p9_transport
*p9_trans_create_fd(int rfd
, int wfd
)
164 struct p9_transport
*trans
;
166 if (rfd
== ~0 || wfd
== ~0) {
167 printk(KERN_ERR
"v9fs: Insufficient options for proto=fd\n");
168 return ERR_PTR(-ENOPROTOOPT
);
171 trans
= kmalloc(sizeof(struct p9_transport
), GFP_KERNEL
);
173 return ERR_PTR(-ENOMEM
);
175 trans
->write
= p9_fd_write
;
176 trans
->read
= p9_fd_read
;
177 trans
->close
= p9_fd_close
;
178 trans
->poll
= p9_fd_poll
;
180 err
= p9_fd_open(trans
, rfd
, wfd
);
190 EXPORT_SYMBOL(p9_trans_create_fd
);
192 static int p9_socket_open(struct p9_transport
*trans
, struct socket
*csocket
)
196 csocket
->sk
->sk_allocation
= GFP_NOIO
;
197 fd
= sock_map_fd(csocket
);
199 P9_EPRINTK(KERN_ERR
, "p9_socket_open: failed to map fd\n");
203 ret
= p9_fd_open(trans
, fd
, fd
);
205 P9_EPRINTK(KERN_ERR
, "p9_socket_open: failed to open fd\n");
210 ((struct p9_trans_fd
*)trans
->priv
)->rd
->f_flags
|= O_NONBLOCK
;
215 static int p9_fd_open(struct p9_transport
*trans
, int rfd
, int wfd
)
217 struct p9_trans_fd
*ts
= kmalloc(sizeof(struct p9_trans_fd
),
224 if (!ts
->rd
|| !ts
->wr
) {
234 trans
->status
= Connected
;
240 * p9_fd_read- read from a fd
241 * @v9ses: session information
242 * @v: buffer to receive data into
243 * @len: size of receive buffer
246 static int p9_fd_read(struct p9_transport
*trans
, void *v
, int len
)
249 struct p9_trans_fd
*ts
= NULL
;
251 if (trans
&& trans
->status
!= Disconnected
)
257 if (!(ts
->rd
->f_flags
& O_NONBLOCK
))
258 P9_DPRINTK(P9_DEBUG_ERROR
, "blocking read ...\n");
260 ret
= kernel_read(ts
->rd
, ts
->rd
->f_pos
, v
, len
);
261 if (ret
<= 0 && ret
!= -ERESTARTSYS
&& ret
!= -EAGAIN
)
262 trans
->status
= Disconnected
;
267 * p9_fd_write - write to a socket
268 * @v9ses: session information
269 * @v: buffer to send data from
270 * @len: size of send buffer
273 static int p9_fd_write(struct p9_transport
*trans
, void *v
, int len
)
277 struct p9_trans_fd
*ts
= NULL
;
279 if (trans
&& trans
->status
!= Disconnected
)
285 if (!(ts
->wr
->f_flags
& O_NONBLOCK
))
286 P9_DPRINTK(P9_DEBUG_ERROR
, "blocking write ...\n");
290 /* The cast to a user pointer is valid due to the set_fs() */
291 ret
= vfs_write(ts
->wr
, (void __user
*)v
, len
, &ts
->wr
->f_pos
);
294 if (ret
<= 0 && ret
!= -ERESTARTSYS
&& ret
!= -EAGAIN
)
295 trans
->status
= Disconnected
;
300 p9_fd_poll(struct p9_transport
*trans
, struct poll_table_struct
*pt
)
303 struct p9_trans_fd
*ts
= NULL
;
306 if (trans
&& trans
->status
== Connected
)
312 if (!ts
->rd
->f_op
|| !ts
->rd
->f_op
->poll
)
315 if (!ts
->wr
->f_op
|| !ts
->wr
->f_op
->poll
)
321 ret
= ts
->rd
->f_op
->poll(ts
->rd
, pt
);
325 if (ts
->rd
!= ts
->wr
) {
326 n
= ts
->wr
->f_op
->poll(ts
->wr
, pt
);
331 ret
= (ret
& ~POLLOUT
) | (n
& ~POLLIN
);
340 * p9_sock_close - shutdown socket
341 * @trans: private socket structure
344 static void p9_fd_close(struct p9_transport
*trans
)
346 struct p9_trans_fd
*ts
;
351 ts
= xchg(&trans
->priv
, NULL
);
356 trans
->status
= Disconnected
;