xref: /openbmc/linux/net/9p/trans_fd.c (revision bd238fb4)
1bd238fb4SLatchesar Ionkov /*
2bd238fb4SLatchesar Ionkov  * linux/fs/9p/trans_fd.c
3bd238fb4SLatchesar Ionkov  *
4bd238fb4SLatchesar Ionkov  * Fd transport layer.  Includes deprecated socket layer.
5bd238fb4SLatchesar Ionkov  *
6bd238fb4SLatchesar Ionkov  *  Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
7bd238fb4SLatchesar Ionkov  *  Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
8bd238fb4SLatchesar Ionkov  *  Copyright (C) 2004-2005 by Eric Van Hensbergen <ericvh@gmail.com>
9bd238fb4SLatchesar Ionkov  *  Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
10bd238fb4SLatchesar Ionkov  *
11bd238fb4SLatchesar Ionkov  *  This program is free software; you can redistribute it and/or modify
12bd238fb4SLatchesar Ionkov  *  it under the terms of the GNU General Public License version 2
13bd238fb4SLatchesar Ionkov  *  as published by the Free Software Foundation.
14bd238fb4SLatchesar Ionkov  *
15bd238fb4SLatchesar Ionkov  *  This program is distributed in the hope that it will be useful,
16bd238fb4SLatchesar Ionkov  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17bd238fb4SLatchesar Ionkov  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18bd238fb4SLatchesar Ionkov  *  GNU General Public License for more details.
19bd238fb4SLatchesar Ionkov  *
20bd238fb4SLatchesar Ionkov  *  You should have received a copy of the GNU General Public License
21bd238fb4SLatchesar Ionkov  *  along with this program; if not, write to:
22bd238fb4SLatchesar Ionkov  *  Free Software Foundation
23bd238fb4SLatchesar Ionkov  *  51 Franklin Street, Fifth Floor
24bd238fb4SLatchesar Ionkov  *  Boston, MA  02111-1301  USA
25bd238fb4SLatchesar Ionkov  *
26bd238fb4SLatchesar Ionkov  */
27bd238fb4SLatchesar Ionkov 
28bd238fb4SLatchesar Ionkov #include <linux/in.h>
29bd238fb4SLatchesar Ionkov #include <linux/module.h>
30bd238fb4SLatchesar Ionkov #include <linux/net.h>
31bd238fb4SLatchesar Ionkov #include <linux/ipv6.h>
32bd238fb4SLatchesar Ionkov #include <linux/errno.h>
33bd238fb4SLatchesar Ionkov #include <linux/kernel.h>
34bd238fb4SLatchesar Ionkov #include <linux/un.h>
35bd238fb4SLatchesar Ionkov #include <linux/uaccess.h>
36bd238fb4SLatchesar Ionkov #include <linux/inet.h>
37bd238fb4SLatchesar Ionkov #include <linux/idr.h>
38bd238fb4SLatchesar Ionkov #include <linux/file.h>
39bd238fb4SLatchesar Ionkov #include <net/9p/9p.h>
40bd238fb4SLatchesar Ionkov #include <net/9p/transport.h>
41bd238fb4SLatchesar Ionkov 
42bd238fb4SLatchesar Ionkov #define P9_PORT 564
43bd238fb4SLatchesar Ionkov 
44bd238fb4SLatchesar Ionkov struct p9_trans_fd {
45bd238fb4SLatchesar Ionkov 	struct file *rd;
46bd238fb4SLatchesar Ionkov 	struct file *wr;
47bd238fb4SLatchesar Ionkov };
48bd238fb4SLatchesar Ionkov 
49bd238fb4SLatchesar Ionkov static int p9_socket_open(struct p9_transport *trans, struct socket *csocket);
50bd238fb4SLatchesar Ionkov static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd);
51bd238fb4SLatchesar Ionkov static int p9_fd_read(struct p9_transport *trans, void *v, int len);
52bd238fb4SLatchesar Ionkov static int p9_fd_write(struct p9_transport *trans, void *v, int len);
53bd238fb4SLatchesar Ionkov static unsigned int p9_fd_poll(struct p9_transport *trans,
54bd238fb4SLatchesar Ionkov 						struct poll_table_struct *pt);
55bd238fb4SLatchesar Ionkov static void p9_fd_close(struct p9_transport *trans);
56bd238fb4SLatchesar Ionkov 
57bd238fb4SLatchesar Ionkov struct p9_transport *p9_trans_create_tcp(const char *addr, int port)
58bd238fb4SLatchesar Ionkov {
59bd238fb4SLatchesar Ionkov 	int err;
60bd238fb4SLatchesar Ionkov 	struct p9_transport *trans;
61bd238fb4SLatchesar Ionkov 	struct socket *csocket;
62bd238fb4SLatchesar Ionkov 	struct sockaddr_in sin_server;
63bd238fb4SLatchesar Ionkov 
64bd238fb4SLatchesar Ionkov 	csocket = NULL;
65bd238fb4SLatchesar Ionkov 	trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL);
66bd238fb4SLatchesar Ionkov 	if (!trans)
67bd238fb4SLatchesar Ionkov 		return ERR_PTR(-ENOMEM);
68bd238fb4SLatchesar Ionkov 
69bd238fb4SLatchesar Ionkov 	trans->write = p9_fd_write;
70bd238fb4SLatchesar Ionkov 	trans->read = p9_fd_read;
71bd238fb4SLatchesar Ionkov 	trans->close = p9_fd_close;
72bd238fb4SLatchesar Ionkov 	trans->poll = p9_fd_poll;
73bd238fb4SLatchesar Ionkov 
74bd238fb4SLatchesar Ionkov 	sin_server.sin_family = AF_INET;
75bd238fb4SLatchesar Ionkov 	sin_server.sin_addr.s_addr = in_aton(addr);
76bd238fb4SLatchesar Ionkov 	sin_server.sin_port = htons(port);
77bd238fb4SLatchesar Ionkov 	sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
78bd238fb4SLatchesar Ionkov 
79bd238fb4SLatchesar Ionkov 	if (!csocket) {
80bd238fb4SLatchesar Ionkov 		P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
81bd238fb4SLatchesar Ionkov 		err = -EIO;
82bd238fb4SLatchesar Ionkov 		goto error;
83bd238fb4SLatchesar Ionkov 	}
84bd238fb4SLatchesar Ionkov 
85bd238fb4SLatchesar Ionkov 	err = csocket->ops->connect(csocket,
86bd238fb4SLatchesar Ionkov 				    (struct sockaddr *)&sin_server,
87bd238fb4SLatchesar Ionkov 				    sizeof(struct sockaddr_in), 0);
88bd238fb4SLatchesar Ionkov 	if (err < 0) {
89bd238fb4SLatchesar Ionkov 		P9_EPRINTK(KERN_ERR,
90bd238fb4SLatchesar Ionkov 			"p9_trans_tcp: problem connecting socket to %s\n",
91bd238fb4SLatchesar Ionkov 			addr);
92bd238fb4SLatchesar Ionkov 		goto error;
93bd238fb4SLatchesar Ionkov 	}
94bd238fb4SLatchesar Ionkov 
95bd238fb4SLatchesar Ionkov 	err = p9_socket_open(trans, csocket);
96bd238fb4SLatchesar Ionkov 	if (err < 0)
97bd238fb4SLatchesar Ionkov 		goto error;
98bd238fb4SLatchesar Ionkov 
99bd238fb4SLatchesar Ionkov 	return trans;
100bd238fb4SLatchesar Ionkov 
101bd238fb4SLatchesar Ionkov error:
102bd238fb4SLatchesar Ionkov 	if (csocket)
103bd238fb4SLatchesar Ionkov 		sock_release(csocket);
104bd238fb4SLatchesar Ionkov 
105bd238fb4SLatchesar Ionkov 	kfree(trans);
106bd238fb4SLatchesar Ionkov 	return ERR_PTR(err);
107bd238fb4SLatchesar Ionkov }
108bd238fb4SLatchesar Ionkov EXPORT_SYMBOL(p9_trans_create_tcp);
109bd238fb4SLatchesar Ionkov 
110bd238fb4SLatchesar Ionkov struct p9_transport *p9_trans_create_unix(const char *addr)
111bd238fb4SLatchesar Ionkov {
112bd238fb4SLatchesar Ionkov 	int err;
113bd238fb4SLatchesar Ionkov 	struct socket *csocket;
114bd238fb4SLatchesar Ionkov 	struct sockaddr_un sun_server;
115bd238fb4SLatchesar Ionkov 	struct p9_transport *trans;
116bd238fb4SLatchesar Ionkov 
117bd238fb4SLatchesar Ionkov 	csocket = NULL;
118bd238fb4SLatchesar Ionkov 	trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL);
119bd238fb4SLatchesar Ionkov 	if (!trans)
120bd238fb4SLatchesar Ionkov 		return ERR_PTR(-ENOMEM);
121bd238fb4SLatchesar Ionkov 
122bd238fb4SLatchesar Ionkov 	trans->write = p9_fd_write;
123bd238fb4SLatchesar Ionkov 	trans->read = p9_fd_read;
124bd238fb4SLatchesar Ionkov 	trans->close = p9_fd_close;
125bd238fb4SLatchesar Ionkov 	trans->poll = p9_fd_poll;
126bd238fb4SLatchesar Ionkov 
127bd238fb4SLatchesar Ionkov 	if (strlen(addr) > UNIX_PATH_MAX) {
128bd238fb4SLatchesar Ionkov 		P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
129bd238fb4SLatchesar Ionkov 			addr);
130bd238fb4SLatchesar Ionkov 		err = -ENAMETOOLONG;
131bd238fb4SLatchesar Ionkov 		goto error;
132bd238fb4SLatchesar Ionkov 	}
133bd238fb4SLatchesar Ionkov 
134bd238fb4SLatchesar Ionkov 	sun_server.sun_family = PF_UNIX;
135bd238fb4SLatchesar Ionkov 	strcpy(sun_server.sun_path, addr);
136bd238fb4SLatchesar Ionkov 	sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
137bd238fb4SLatchesar Ionkov 	err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
138bd238fb4SLatchesar Ionkov 			sizeof(struct sockaddr_un) - 1, 0);
139bd238fb4SLatchesar Ionkov 	if (err < 0) {
140bd238fb4SLatchesar Ionkov 		P9_EPRINTK(KERN_ERR,
141bd238fb4SLatchesar Ionkov 			"p9_trans_unix: problem connecting socket: %s: %d\n",
142bd238fb4SLatchesar Ionkov 			addr, err);
143bd238fb4SLatchesar Ionkov 		goto error;
144bd238fb4SLatchesar Ionkov 	}
145bd238fb4SLatchesar Ionkov 
146bd238fb4SLatchesar Ionkov 	err = p9_socket_open(trans, csocket);
147bd238fb4SLatchesar Ionkov 	if (err < 0)
148bd238fb4SLatchesar Ionkov 		goto error;
149bd238fb4SLatchesar Ionkov 
150bd238fb4SLatchesar Ionkov 	return trans;
151bd238fb4SLatchesar Ionkov 
152bd238fb4SLatchesar Ionkov error:
153bd238fb4SLatchesar Ionkov 	if (csocket)
154bd238fb4SLatchesar Ionkov 		sock_release(csocket);
155bd238fb4SLatchesar Ionkov 
156bd238fb4SLatchesar Ionkov 	kfree(trans);
157bd238fb4SLatchesar Ionkov 	return ERR_PTR(err);
158bd238fb4SLatchesar Ionkov }
159bd238fb4SLatchesar Ionkov EXPORT_SYMBOL(p9_trans_create_unix);
160bd238fb4SLatchesar Ionkov 
161bd238fb4SLatchesar Ionkov struct p9_transport *p9_trans_create_fd(int rfd, int wfd)
162bd238fb4SLatchesar Ionkov {
163bd238fb4SLatchesar Ionkov 	int err;
164bd238fb4SLatchesar Ionkov 	struct p9_transport *trans;
165bd238fb4SLatchesar Ionkov 
166bd238fb4SLatchesar Ionkov 	if (rfd == ~0 || wfd == ~0) {
167bd238fb4SLatchesar Ionkov 		printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
168bd238fb4SLatchesar Ionkov 		return ERR_PTR(-ENOPROTOOPT);
169bd238fb4SLatchesar Ionkov 	}
170bd238fb4SLatchesar Ionkov 
171bd238fb4SLatchesar Ionkov 	trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL);
172bd238fb4SLatchesar Ionkov 	if (!trans)
173bd238fb4SLatchesar Ionkov 		return ERR_PTR(-ENOMEM);
174bd238fb4SLatchesar Ionkov 
175bd238fb4SLatchesar Ionkov 	trans->write = p9_fd_write;
176bd238fb4SLatchesar Ionkov 	trans->read = p9_fd_read;
177bd238fb4SLatchesar Ionkov 	trans->close = p9_fd_close;
178bd238fb4SLatchesar Ionkov 	trans->poll = p9_fd_poll;
179bd238fb4SLatchesar Ionkov 
180bd238fb4SLatchesar Ionkov 	err = p9_fd_open(trans, rfd, wfd);
181bd238fb4SLatchesar Ionkov 	if (err < 0)
182bd238fb4SLatchesar Ionkov 		goto error;
183bd238fb4SLatchesar Ionkov 
184bd238fb4SLatchesar Ionkov 	return trans;
185bd238fb4SLatchesar Ionkov 
186bd238fb4SLatchesar Ionkov error:
187bd238fb4SLatchesar Ionkov 	kfree(trans);
188bd238fb4SLatchesar Ionkov 	return ERR_PTR(err);
189bd238fb4SLatchesar Ionkov }
190bd238fb4SLatchesar Ionkov EXPORT_SYMBOL(p9_trans_create_fd);
191bd238fb4SLatchesar Ionkov 
192bd238fb4SLatchesar Ionkov static int p9_socket_open(struct p9_transport *trans, struct socket *csocket)
193bd238fb4SLatchesar Ionkov {
194bd238fb4SLatchesar Ionkov 	int fd, ret;
195bd238fb4SLatchesar Ionkov 
196bd238fb4SLatchesar Ionkov 	csocket->sk->sk_allocation = GFP_NOIO;
197bd238fb4SLatchesar Ionkov 	fd = sock_map_fd(csocket);
198bd238fb4SLatchesar Ionkov 	if (fd < 0) {
199bd238fb4SLatchesar Ionkov 		P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n");
200bd238fb4SLatchesar Ionkov 		return fd;
201bd238fb4SLatchesar Ionkov 	}
202bd238fb4SLatchesar Ionkov 
203bd238fb4SLatchesar Ionkov 	ret = p9_fd_open(trans, fd, fd);
204bd238fb4SLatchesar Ionkov 	if (ret < 0) {
205bd238fb4SLatchesar Ionkov 		P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n");
206bd238fb4SLatchesar Ionkov 		sockfd_put(csocket);
207bd238fb4SLatchesar Ionkov 		return ret;
208bd238fb4SLatchesar Ionkov 	}
209bd238fb4SLatchesar Ionkov 
210bd238fb4SLatchesar Ionkov 	((struct p9_trans_fd *)trans->priv)->rd->f_flags |= O_NONBLOCK;
211bd238fb4SLatchesar Ionkov 
212bd238fb4SLatchesar Ionkov 	return 0;
213bd238fb4SLatchesar Ionkov }
214bd238fb4SLatchesar Ionkov 
215bd238fb4SLatchesar Ionkov static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd)
216bd238fb4SLatchesar Ionkov {
217bd238fb4SLatchesar Ionkov 	struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd),
218bd238fb4SLatchesar Ionkov 					   GFP_KERNEL);
219bd238fb4SLatchesar Ionkov 	if (!ts)
220bd238fb4SLatchesar Ionkov 		return -ENOMEM;
221bd238fb4SLatchesar Ionkov 
222bd238fb4SLatchesar Ionkov 	ts->rd = fget(rfd);
223bd238fb4SLatchesar Ionkov 	ts->wr = fget(wfd);
224bd238fb4SLatchesar Ionkov 	if (!ts->rd || !ts->wr) {
225bd238fb4SLatchesar Ionkov 		if (ts->rd)
226bd238fb4SLatchesar Ionkov 			fput(ts->rd);
227bd238fb4SLatchesar Ionkov 		if (ts->wr)
228bd238fb4SLatchesar Ionkov 			fput(ts->wr);
229bd238fb4SLatchesar Ionkov 		kfree(ts);
230bd238fb4SLatchesar Ionkov 		return -EIO;
231bd238fb4SLatchesar Ionkov 	}
232bd238fb4SLatchesar Ionkov 
233bd238fb4SLatchesar Ionkov 	trans->priv = ts;
234bd238fb4SLatchesar Ionkov 	trans->status = Connected;
235bd238fb4SLatchesar Ionkov 
236bd238fb4SLatchesar Ionkov 	return 0;
237bd238fb4SLatchesar Ionkov }
238bd238fb4SLatchesar Ionkov 
239bd238fb4SLatchesar Ionkov /**
240bd238fb4SLatchesar Ionkov  * p9_fd_read- read from a fd
241bd238fb4SLatchesar Ionkov  * @v9ses: session information
242bd238fb4SLatchesar Ionkov  * @v: buffer to receive data into
243bd238fb4SLatchesar Ionkov  * @len: size of receive buffer
244bd238fb4SLatchesar Ionkov  *
245bd238fb4SLatchesar Ionkov  */
246bd238fb4SLatchesar Ionkov static int p9_fd_read(struct p9_transport *trans, void *v, int len)
247bd238fb4SLatchesar Ionkov {
248bd238fb4SLatchesar Ionkov 	int ret;
249bd238fb4SLatchesar Ionkov 	struct p9_trans_fd *ts = NULL;
250bd238fb4SLatchesar Ionkov 
251bd238fb4SLatchesar Ionkov 	if (trans && trans->status != Disconnected)
252bd238fb4SLatchesar Ionkov 		ts = trans->priv;
253bd238fb4SLatchesar Ionkov 
254bd238fb4SLatchesar Ionkov 	if (!ts)
255bd238fb4SLatchesar Ionkov 		return -EREMOTEIO;
256bd238fb4SLatchesar Ionkov 
257bd238fb4SLatchesar Ionkov 	if (!(ts->rd->f_flags & O_NONBLOCK))
258bd238fb4SLatchesar Ionkov 		P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n");
259bd238fb4SLatchesar Ionkov 
260bd238fb4SLatchesar Ionkov 	ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
261bd238fb4SLatchesar Ionkov 	if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
262bd238fb4SLatchesar Ionkov 		trans->status = Disconnected;
263bd238fb4SLatchesar Ionkov 	return ret;
264bd238fb4SLatchesar Ionkov }
265bd238fb4SLatchesar Ionkov 
266bd238fb4SLatchesar Ionkov /**
267bd238fb4SLatchesar Ionkov  * p9_fd_write - write to a socket
268bd238fb4SLatchesar Ionkov  * @v9ses: session information
269bd238fb4SLatchesar Ionkov  * @v: buffer to send data from
270bd238fb4SLatchesar Ionkov  * @len: size of send buffer
271bd238fb4SLatchesar Ionkov  *
272bd238fb4SLatchesar Ionkov  */
273bd238fb4SLatchesar Ionkov static int p9_fd_write(struct p9_transport *trans, void *v, int len)
274bd238fb4SLatchesar Ionkov {
275bd238fb4SLatchesar Ionkov 	int ret;
276bd238fb4SLatchesar Ionkov 	mm_segment_t oldfs;
277bd238fb4SLatchesar Ionkov 	struct p9_trans_fd *ts = NULL;
278bd238fb4SLatchesar Ionkov 
279bd238fb4SLatchesar Ionkov 	if (trans && trans->status != Disconnected)
280bd238fb4SLatchesar Ionkov 		ts = trans->priv;
281bd238fb4SLatchesar Ionkov 
282bd238fb4SLatchesar Ionkov 	if (!ts)
283bd238fb4SLatchesar Ionkov 		return -EREMOTEIO;
284bd238fb4SLatchesar Ionkov 
285bd238fb4SLatchesar Ionkov 	if (!(ts->wr->f_flags & O_NONBLOCK))
286bd238fb4SLatchesar Ionkov 		P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n");
287bd238fb4SLatchesar Ionkov 
288bd238fb4SLatchesar Ionkov 	oldfs = get_fs();
289bd238fb4SLatchesar Ionkov 	set_fs(get_ds());
290bd238fb4SLatchesar Ionkov 	/* The cast to a user pointer is valid due to the set_fs() */
291bd238fb4SLatchesar Ionkov 	ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
292bd238fb4SLatchesar Ionkov 	set_fs(oldfs);
293bd238fb4SLatchesar Ionkov 
294bd238fb4SLatchesar Ionkov 	if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
295bd238fb4SLatchesar Ionkov 		trans->status = Disconnected;
296bd238fb4SLatchesar Ionkov 	return ret;
297bd238fb4SLatchesar Ionkov }
298bd238fb4SLatchesar Ionkov 
299bd238fb4SLatchesar Ionkov static unsigned int
300bd238fb4SLatchesar Ionkov p9_fd_poll(struct p9_transport *trans, struct poll_table_struct *pt)
301bd238fb4SLatchesar Ionkov {
302bd238fb4SLatchesar Ionkov 	int ret, n;
303bd238fb4SLatchesar Ionkov 	struct p9_trans_fd *ts = NULL;
304bd238fb4SLatchesar Ionkov 	mm_segment_t oldfs;
305bd238fb4SLatchesar Ionkov 
306bd238fb4SLatchesar Ionkov 	if (trans && trans->status == Connected)
307bd238fb4SLatchesar Ionkov 		ts = trans->priv;
308bd238fb4SLatchesar Ionkov 
309bd238fb4SLatchesar Ionkov 	if (!ts)
310bd238fb4SLatchesar Ionkov 		return -EREMOTEIO;
311bd238fb4SLatchesar Ionkov 
312bd238fb4SLatchesar Ionkov 	if (!ts->rd->f_op || !ts->rd->f_op->poll)
313bd238fb4SLatchesar Ionkov 		return -EIO;
314bd238fb4SLatchesar Ionkov 
315bd238fb4SLatchesar Ionkov 	if (!ts->wr->f_op || !ts->wr->f_op->poll)
316bd238fb4SLatchesar Ionkov 		return -EIO;
317bd238fb4SLatchesar Ionkov 
318bd238fb4SLatchesar Ionkov 	oldfs = get_fs();
319bd238fb4SLatchesar Ionkov 	set_fs(get_ds());
320bd238fb4SLatchesar Ionkov 
321bd238fb4SLatchesar Ionkov 	ret = ts->rd->f_op->poll(ts->rd, pt);
322bd238fb4SLatchesar Ionkov 	if (ret < 0)
323bd238fb4SLatchesar Ionkov 		goto end;
324bd238fb4SLatchesar Ionkov 
325bd238fb4SLatchesar Ionkov 	if (ts->rd != ts->wr) {
326bd238fb4SLatchesar Ionkov 		n = ts->wr->f_op->poll(ts->wr, pt);
327bd238fb4SLatchesar Ionkov 		if (n < 0) {
328bd238fb4SLatchesar Ionkov 			ret = n;
329bd238fb4SLatchesar Ionkov 			goto end;
330bd238fb4SLatchesar Ionkov 		}
331bd238fb4SLatchesar Ionkov 		ret = (ret & ~POLLOUT) | (n & ~POLLIN);
332bd238fb4SLatchesar Ionkov 	}
333bd238fb4SLatchesar Ionkov 
334bd238fb4SLatchesar Ionkov end:
335bd238fb4SLatchesar Ionkov 	set_fs(oldfs);
336bd238fb4SLatchesar Ionkov 	return ret;
337bd238fb4SLatchesar Ionkov }
338bd238fb4SLatchesar Ionkov 
339bd238fb4SLatchesar Ionkov /**
340bd238fb4SLatchesar Ionkov  * p9_sock_close - shutdown socket
341bd238fb4SLatchesar Ionkov  * @trans: private socket structure
342bd238fb4SLatchesar Ionkov  *
343bd238fb4SLatchesar Ionkov  */
344bd238fb4SLatchesar Ionkov static void p9_fd_close(struct p9_transport *trans)
345bd238fb4SLatchesar Ionkov {
346bd238fb4SLatchesar Ionkov 	struct p9_trans_fd *ts;
347bd238fb4SLatchesar Ionkov 
348bd238fb4SLatchesar Ionkov 	if (!trans)
349bd238fb4SLatchesar Ionkov 		return;
350bd238fb4SLatchesar Ionkov 
351bd238fb4SLatchesar Ionkov 	ts = xchg(&trans->priv, NULL);
352bd238fb4SLatchesar Ionkov 
353bd238fb4SLatchesar Ionkov 	if (!ts)
354bd238fb4SLatchesar Ionkov 		return;
355bd238fb4SLatchesar Ionkov 
356bd238fb4SLatchesar Ionkov 	trans->status = Disconnected;
357bd238fb4SLatchesar Ionkov 	if (ts->rd)
358bd238fb4SLatchesar Ionkov 		fput(ts->rd);
359bd238fb4SLatchesar Ionkov 	if (ts->wr)
360bd238fb4SLatchesar Ionkov 		fput(ts->wr);
361bd238fb4SLatchesar Ionkov 	kfree(ts);
362bd238fb4SLatchesar Ionkov }
363bd238fb4SLatchesar Ionkov 
364