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