X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2F9p%2Ftrans_fd.c;fp=fs%2F9p%2Ftrans_fd.c;h=5b2ce21b10fab55b6bf6e5db54b615d3c961c2ea;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=34d43355beb7212c4226bd248aa68e4bd0e2612e;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/fs/9p/trans_fd.c b/fs/9p/trans_fd.c index 34d43355b..5b2ce21b1 100644 --- a/fs/9p/trans_fd.c +++ b/fs/9p/trans_fd.c @@ -1,16 +1,15 @@ /* * linux/fs/9p/trans_fd.c * - * Fd transport layer. Includes deprecated socket layer. + * File Descriptor Transport Layer * - * Copyright (C) 2006 by Russ Cox - * Copyright (C) 2004-2005 by Latchesar Ionkov - * Copyright (C) 2004-2005 by Eric Van Hensbergen - * Copyright (C) 1997-2002 by Ron Minnich + * Copyright (C) 2005 by Latchesar Ionkov + * Copyright (C) 2005 by Eric Van Hensbergen * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -25,7 +24,7 @@ * */ -#include +#include #include #include #include @@ -41,119 +40,89 @@ #include "v9fs.h" #include "transport.h" -#define V9FS_PORT 564 - struct v9fs_trans_fd { - struct file *rd; - struct file *wr; + struct file *in_file; + struct file *out_file; }; /** - * v9fs_fd_read- read from a fd + * v9fs_fd_recv - receive from a socket * @v9ses: session information * @v: buffer to receive data into * @len: size of receive buffer * */ -static int v9fs_fd_read(struct v9fs_transport *trans, void *v, int len) -{ - int ret; - struct v9fs_trans_fd *ts; - if (!trans || trans->status == Disconnected || !(ts = trans->priv)) - return -EREMOTEIO; +static int v9fs_fd_recv(struct v9fs_transport *trans, void *v, int len) +{ + struct v9fs_trans_fd *ts = trans ? trans->priv : NULL; - if (!(ts->rd->f_flags & O_NONBLOCK)) - dprintk(DEBUG_ERROR, "blocking read ...\n"); + if (!trans || trans->status != Connected || !ts) + return -EIO; - ret = kernel_read(ts->rd, ts->rd->f_pos, v, len); - if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) - trans->status = Disconnected; - return ret; + return kernel_read(ts->in_file, ts->in_file->f_pos, v, len); } /** - * v9fs_fd_write - write to a socket + * v9fs_fd_send - send to a socket * @v9ses: session information * @v: buffer to send data from * @len: size of send buffer * */ -static int v9fs_fd_write(struct v9fs_transport *trans, void *v, int len) -{ - int ret; - mm_segment_t oldfs; - struct v9fs_trans_fd *ts; - if (!trans || trans->status == Disconnected || !(ts = trans->priv)) - return -EREMOTEIO; +static int v9fs_fd_send(struct v9fs_transport *trans, void *v, int len) +{ + struct v9fs_trans_fd *ts = trans ? trans->priv : NULL; + mm_segment_t oldfs = get_fs(); + int ret = 0; - if (!(ts->wr->f_flags & O_NONBLOCK)) - dprintk(DEBUG_ERROR, "blocking write ...\n"); + if (!trans || trans->status != Connected || !ts) + return -EIO; oldfs = get_fs(); set_fs(get_ds()); /* The cast to a user pointer is valid due to the set_fs() */ - ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos); + ret = vfs_write(ts->out_file, (void __user *)v, len, &ts->out_file->f_pos); set_fs(oldfs); - if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) - trans->status = Disconnected; return ret; } -static unsigned int -v9fs_fd_poll(struct v9fs_transport *trans, struct poll_table_struct *pt) -{ - int ret, n; - struct v9fs_trans_fd *ts; - mm_segment_t oldfs; - - if (!trans || trans->status != Connected || !(ts = trans->priv)) - return -EREMOTEIO; - - if (!ts->rd->f_op || !ts->rd->f_op->poll) - return -EIO; - - if (!ts->wr->f_op || !ts->wr->f_op->poll) - return -EIO; - - oldfs = get_fs(); - set_fs(get_ds()); +/** + * v9fs_fd_init - initialize file descriptor transport + * @v9ses: session information + * @addr: address of server to mount + * @data: mount options + * + */ - ret = ts->rd->f_op->poll(ts->rd, pt); - if (ret < 0) - goto end; +static int +v9fs_fd_init(struct v9fs_session_info *v9ses, const char *addr, char *data) +{ + struct v9fs_trans_fd *ts = NULL; + struct v9fs_transport *trans = v9ses->transport; - if (ts->rd != ts->wr) { - n = ts->wr->f_op->poll(ts->wr, pt); - if (n < 0) { - ret = n; - goto end; - } - ret = (ret & ~POLLOUT) | (n & ~POLLIN); + if((v9ses->wfdno == ~0) || (v9ses->rfdno == ~0)) { + printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n"); + return -ENOPROTOOPT; } - end: - set_fs(oldfs); - return ret; -} + ts = kmalloc(sizeof(struct v9fs_trans_fd), GFP_KERNEL); -static int v9fs_fd_open(struct v9fs_session_info *v9ses, int rfd, int wfd) -{ - struct v9fs_transport *trans = v9ses->transport; - struct v9fs_trans_fd *ts = kmalloc(sizeof(struct v9fs_trans_fd), - GFP_KERNEL); if (!ts) return -ENOMEM; - ts->rd = fget(rfd); - ts->wr = fget(wfd); - if (!ts->rd || !ts->wr) { - if (ts->rd) - fput(ts->rd); - if (ts->wr) - fput(ts->wr); + ts->in_file = fget( v9ses->rfdno ); + ts->out_file = fget( v9ses->wfdno ); + + if (!ts->in_file || !ts->out_file) { + if (ts->in_file) + fput(ts->in_file); + + if (ts->out_file) + fput(ts->out_file); + kfree(ts); return -EIO; } @@ -164,105 +133,13 @@ static int v9fs_fd_open(struct v9fs_session_info *v9ses, int rfd, int wfd) return 0; } -static int v9fs_fd_init(struct v9fs_session_info *v9ses, const char *addr, - char *data) -{ - if (v9ses->rfdno == ~0 || v9ses->wfdno == ~0) { - printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n"); - return -ENOPROTOOPT; - } - - return v9fs_fd_open(v9ses, v9ses->rfdno, v9ses->wfdno); -} - -static int v9fs_socket_open(struct v9fs_session_info *v9ses, - struct socket *csocket) -{ - int fd, ret; - - csocket->sk->sk_allocation = GFP_NOIO; - if ((fd = sock_map_fd(csocket)) < 0) { - eprintk(KERN_ERR, "v9fs_socket_open: failed to map fd\n"); - ret = fd; - release_csocket: - sock_release(csocket); - return ret; - } - - if ((ret = v9fs_fd_open(v9ses, fd, fd)) < 0) { - sockfd_put(csocket); - eprintk(KERN_ERR, "v9fs_socket_open: failed to open fd\n"); - goto release_csocket; - } - - ((struct v9fs_trans_fd *)v9ses->transport->priv)->rd->f_flags |= - O_NONBLOCK; - return 0; -} - -static int v9fs_tcp_init(struct v9fs_session_info *v9ses, const char *addr, - char *data) -{ - int ret; - struct socket *csocket = NULL; - struct sockaddr_in sin_server; - - sin_server.sin_family = AF_INET; - sin_server.sin_addr.s_addr = in_aton(addr); - sin_server.sin_port = htons(v9ses->port); - sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket); - - if (!csocket) { - eprintk(KERN_ERR, "v9fs_trans_tcp: problem creating socket\n"); - return -1; - } - - ret = csocket->ops->connect(csocket, - (struct sockaddr *)&sin_server, - sizeof(struct sockaddr_in), 0); - if (ret < 0) { - eprintk(KERN_ERR, - "v9fs_trans_tcp: problem connecting socket to %s\n", - addr); - return ret; - } - - return v9fs_socket_open(v9ses, csocket); -} - -static int -v9fs_unix_init(struct v9fs_session_info *v9ses, const char *addr, char *data) -{ - int ret; - struct socket *csocket; - struct sockaddr_un sun_server; - - if (strlen(addr) > UNIX_PATH_MAX) { - eprintk(KERN_ERR, "v9fs_trans_unix: address too long: %s\n", - addr); - return -ENAMETOOLONG; - } - - sun_server.sun_family = PF_UNIX; - strcpy(sun_server.sun_path, addr); - sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket); - ret = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server, - sizeof(struct sockaddr_un) - 1, 0); - if (ret < 0) { - eprintk(KERN_ERR, - "v9fs_trans_unix: problem connecting socket: %s: %d\n", - addr, ret); - return ret; - } - - return v9fs_socket_open(v9ses, csocket); -} /** - * v9fs_sock_close - shutdown socket + * v9fs_fd_close - shutdown file descriptor * @trans: private socket structure * */ + static void v9fs_fd_close(struct v9fs_transport *trans) { struct v9fs_trans_fd *ts; @@ -276,33 +153,64 @@ static void v9fs_fd_close(struct v9fs_transport *trans) return; trans->status = Disconnected; - if (ts->rd) - fput(ts->rd); - if (ts->wr) - fput(ts->wr); + if (ts->in_file) + fput(ts->in_file); + + if (ts->out_file) + fput(ts->out_file); + kfree(ts); } +static unsigned int +v9fs_fd_poll(struct v9fs_transport *trans, struct poll_table_struct *pt) +{ + int ret, n; + struct v9fs_trans_fd *ts; + mm_segment_t oldfs; + + if (!trans) + return -EIO; + + ts = trans->priv; + if (trans->status != Connected || !ts) + return -EIO; + + oldfs = get_fs(); + set_fs(get_ds()); + + if (!ts->in_file->f_op || !ts->in_file->f_op->poll) { + ret = -EIO; + goto end; + } + + ret = ts->in_file->f_op->poll(ts->in_file, pt); + + if (ts->out_file != ts->in_file) { + if (!ts->out_file->f_op || !ts->out_file->f_op->poll) { + ret = -EIO; + goto end; + } + + n = ts->out_file->f_op->poll(ts->out_file, pt); + + ret &= ~POLLOUT; + n &= ~POLLIN; + + ret |= n; + } + +end: + set_fs(oldfs); + return ret; +} + + struct v9fs_transport v9fs_trans_fd = { .init = v9fs_fd_init, - .write = v9fs_fd_write, - .read = v9fs_fd_read, + .write = v9fs_fd_send, + .read = v9fs_fd_recv, .close = v9fs_fd_close, .poll = v9fs_fd_poll, }; -struct v9fs_transport v9fs_trans_tcp = { - .init = v9fs_tcp_init, - .write = v9fs_fd_write, - .read = v9fs_fd_read, - .close = v9fs_fd_close, - .poll = v9fs_fd_poll, -}; - -struct v9fs_transport v9fs_trans_unix = { - .init = v9fs_unix_init, - .write = v9fs_fd_write, - .read = v9fs_fd_read, - .close = v9fs_fd_close, - .poll = v9fs_fd_poll, -};