From 992b3f1dbeec401e19a80bdb8c81e5df5381f4c5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 13 Oct 2008 18:45:25 -0500 Subject: 9p-trans_fd: use single poller trans_fd used pool of upto 100 pollers to monitor the r/w fds. The approach makes sense in userspace back when the only available interfaces were poll(2) and select(2). As each event monitor - trigger - handling iteration took O(n) where `n' is the number of watched fds, it makes sense to spread them to many pollers such that the `n' can be divided by the number of pollers. However, this doesn't make any sense in kernel because persistent edge triggered event monitoring is how the whole thing is implemented in the kernel in the first place. This patch converts trans_fd to use single poller which watches all the fds instead of the poll of pollers approach. All the fds are registered for monitoring on creation and only the fds with pending events are scanned when something happens much like how epoll is implemented. This change makes trans_fd fd monitoring more efficient and simpler. Signed-off-by: Tejun Heo Signed-off-by: Eric Van Hensbergen --- net/9p/trans_fd.c | 252 +++++++++++++++++++----------------------------------- 1 file changed, 86 insertions(+), 166 deletions(-) (limited to 'net/9p/trans_fd.c') diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 6dabbdb66651..f84592345573 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -44,7 +44,6 @@ #define P9_PORT 564 #define MAX_SOCK_BUF (64*1024) #define ERREQFLUSH 1 -#define SCHED_TIMEOUT 10 #define MAXPOLLWADDR 2 /** @@ -135,17 +134,16 @@ struct p9_req { struct list_head req_list; }; -struct p9_mux_poll_task { - struct task_struct *task; - struct list_head mux_list; - int muxnum; +struct p9_poll_wait { + struct p9_conn *conn; + wait_queue_t wait; + wait_queue_head_t *wait_addr; }; /** * struct p9_conn - fd mux connection state information * @lock: protects mux_list (?) * @mux_list: list link for mux to manage multiple connections (?) - * @poll_task: task polling on this connection * @msize: maximum size for connection (dup) * @extended: 9p2000.u flag (dup) * @trans: reference to transport instance for this connection @@ -171,7 +169,6 @@ struct p9_mux_poll_task { struct p9_conn { spinlock_t lock; /* protect lock structure */ struct list_head mux_list; - struct p9_mux_poll_task *poll_task; int msize; unsigned char extended; struct p9_trans *trans; @@ -185,8 +182,8 @@ struct p9_conn { int wpos; int wsize; char *wbuf; - wait_queue_t poll_wait[MAXPOLLWADDR]; - wait_queue_head_t *poll_waddr[MAXPOLLWADDR]; + struct list_head poll_pending_link; + struct p9_poll_wait poll_wait[MAXPOLLWADDR]; poll_table pt; struct work_struct rq; struct work_struct wq; @@ -220,12 +217,10 @@ static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, static int p9_fd_write(struct p9_trans *trans, void *v, int len); static int p9_fd_read(struct p9_trans *trans, void *v, int len); -static DEFINE_MUTEX(p9_mux_task_lock); +static DEFINE_SPINLOCK(p9_poll_lock); +static LIST_HEAD(p9_poll_pending_list); static struct workqueue_struct *p9_mux_wq; - -static int p9_mux_num; -static int p9_mux_poll_task_num; -static struct p9_mux_poll_task p9_mux_poll_tasks[100]; +static struct task_struct *p9_poll_task; static void p9_conn_destroy(struct p9_conn *); static unsigned int p9_fd_poll(struct p9_trans *trans, @@ -255,130 +250,23 @@ static void p9_mux_put_tag(struct p9_conn *m, u16 tag) p9_idpool_put(tag, m->tagpool); } -/** - * p9_mux_calc_poll_procs - calculates the number of polling procs - * @muxnum: number of mounts - * - * Calculation is based on the number of mounted v9fs filesystems. - * The current implementation returns sqrt of the number of mounts. - */ - -static int p9_mux_calc_poll_procs(int muxnum) -{ - int n; - - if (p9_mux_poll_task_num) - n = muxnum / p9_mux_poll_task_num + - (muxnum % p9_mux_poll_task_num ? 1 : 0); - else - n = 1; - - if (n > ARRAY_SIZE(p9_mux_poll_tasks)) - n = ARRAY_SIZE(p9_mux_poll_tasks); - - return n; -} - -static int p9_mux_poll_start(struct p9_conn *m) +static void p9_mux_poll_stop(struct p9_conn *m) { - int i, n; - struct p9_mux_poll_task *vpt, *vptlast; - struct task_struct *pproc; - - P9_DPRINTK(P9_DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, p9_mux_num, - p9_mux_poll_task_num); - mutex_lock(&p9_mux_task_lock); - - n = p9_mux_calc_poll_procs(p9_mux_num + 1); - if (n > p9_mux_poll_task_num) { - for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) { - if (p9_mux_poll_tasks[i].task == NULL) { - vpt = &p9_mux_poll_tasks[i]; - P9_DPRINTK(P9_DEBUG_MUX, "create proc %p\n", - vpt); - pproc = kthread_create(p9_poll_proc, vpt, - "v9fs-poll"); - - if (!IS_ERR(pproc)) { - vpt->task = pproc; - INIT_LIST_HEAD(&vpt->mux_list); - vpt->muxnum = 0; - p9_mux_poll_task_num++; - wake_up_process(vpt->task); - } - break; - } - } - - if (i >= ARRAY_SIZE(p9_mux_poll_tasks)) - P9_DPRINTK(P9_DEBUG_ERROR, - "warning: no free poll slots\n"); - } + unsigned long flags; + int i; - n = (p9_mux_num + 1) / p9_mux_poll_task_num + - ((p9_mux_num + 1) % p9_mux_poll_task_num ? 1 : 0); - - vptlast = NULL; - for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) { - vpt = &p9_mux_poll_tasks[i]; - if (vpt->task != NULL) { - vptlast = vpt; - if (vpt->muxnum < n) { - P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i); - list_add(&m->mux_list, &vpt->mux_list); - vpt->muxnum++; - m->poll_task = vpt; - memset(&m->poll_waddr, 0, - sizeof(m->poll_waddr)); - init_poll_funcptr(&m->pt, p9_pollwait); - break; - } - } - } + for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { + struct p9_poll_wait *pwait = &m->poll_wait[i]; - if (i >= ARRAY_SIZE(p9_mux_poll_tasks)) { - if (vptlast == NULL) { - mutex_unlock(&p9_mux_task_lock); - return -ENOMEM; + if (pwait->wait_addr) { + remove_wait_queue(pwait->wait_addr, &pwait->wait); + pwait->wait_addr = NULL; } - - P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i); - list_add(&m->mux_list, &vptlast->mux_list); - vptlast->muxnum++; - m->poll_task = vptlast; - memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); - init_poll_funcptr(&m->pt, p9_pollwait); } - p9_mux_num++; - mutex_unlock(&p9_mux_task_lock); - - return 0; -} - -static void p9_mux_poll_stop(struct p9_conn *m) -{ - int i; - struct p9_mux_poll_task *vpt; - - mutex_lock(&p9_mux_task_lock); - vpt = m->poll_task; - list_del(&m->mux_list); - for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { - if (m->poll_waddr[i] != NULL) { - remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]); - m->poll_waddr[i] = NULL; - } - } - vpt->muxnum--; - if (!vpt->muxnum) { - P9_DPRINTK(P9_DEBUG_MUX, "destroy proc %p\n", vpt); - kthread_stop(vpt->task); - vpt->task = NULL; - p9_mux_poll_task_num--; - } - p9_mux_num--; - mutex_unlock(&p9_mux_task_lock); + spin_lock_irqsave(&p9_poll_lock, flags); + list_del_init(&m->poll_pending_link); + spin_unlock_irqrestore(&p9_poll_lock, flags); } /** @@ -414,11 +302,8 @@ static struct p9_conn *p9_conn_create(struct p9_trans *trans) INIT_LIST_HEAD(&m->unsent_req_list); INIT_WORK(&m->rq, p9_read_work); INIT_WORK(&m->wq, p9_write_work); - n = p9_mux_poll_start(m); - if (n) { - kfree(m); - return ERR_PTR(n); - } + INIT_LIST_HEAD(&m->poll_pending_link); + init_poll_funcptr(&m->pt, p9_pollwait); n = p9_fd_poll(trans, &m->pt); if (n & POLLIN) { @@ -431,11 +316,12 @@ static struct p9_conn *p9_conn_create(struct p9_trans *trans) set_bit(Wpending, &m->wsched); } - for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { - if (IS_ERR(m->poll_waddr[i])) { + for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { + if (IS_ERR(m->poll_wait[i].wait_addr)) { p9_mux_poll_stop(m); kfree(m); - return (void *)m->poll_waddr; /* the error code */ + /* return the error code */ + return (void *)m->poll_wait[i].wait_addr; } } @@ -464,6 +350,23 @@ static void p9_conn_destroy(struct p9_conn *m) kfree(m); } +static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) +{ + struct p9_poll_wait *pwait = + container_of(wait, struct p9_poll_wait, wait); + struct p9_conn *m = pwait->conn; + unsigned long flags; + DECLARE_WAITQUEUE(dummy_wait, p9_poll_task); + + spin_lock_irqsave(&p9_poll_lock, flags); + if (list_empty(&m->poll_pending_link)) + list_add_tail(&m->poll_pending_link, &p9_poll_pending_list); + spin_unlock_irqrestore(&p9_poll_lock, flags); + + /* perform the default wake up operation */ + return default_wake_function(&dummy_wait, mode, sync, key); +} + /** * p9_pollwait - add poll task to the wait queue * @filp: file pointer being polled @@ -476,29 +379,32 @@ static void p9_conn_destroy(struct p9_conn *m) static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) { + struct p9_conn *m = container_of(p, struct p9_conn, pt); + struct p9_poll_wait *pwait = NULL; int i; - struct p9_conn *m; - m = container_of(p, struct p9_conn, pt); - for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) - if (m->poll_waddr[i] == NULL) + for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { + if (m->poll_wait[i].wait_addr == NULL) { + pwait = &m->poll_wait[i]; break; + } + } - if (i >= ARRAY_SIZE(m->poll_waddr)) { + if (!pwait) { P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n"); return; } - m->poll_waddr[i] = wait_address; - if (!wait_address) { P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n"); - m->poll_waddr[i] = ERR_PTR(-EIO); + pwait->wait_addr = ERR_PTR(-EIO); return; } - init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task); - add_wait_queue(wait_address, &m->poll_wait[i]); + pwait->conn = m; + pwait->wait_addr = wait_address; + init_waitqueue_func_entry(&pwait->wait, p9_pollwake); + add_wait_queue(wait_address, &pwait->wait); } /** @@ -553,23 +459,34 @@ static void p9_poll_mux(struct p9_conn *m) static int p9_poll_proc(void *a) { - struct p9_conn *m, *mtmp; - struct p9_mux_poll_task *vpt; + unsigned long flags; - vpt = a; - P9_DPRINTK(P9_DEBUG_MUX, "start %p %p\n", current, vpt); - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); + P9_DPRINTK(P9_DEBUG_MUX, "start %p\n", current); + repeat: + spin_lock_irqsave(&p9_poll_lock, flags); + while (!list_empty(&p9_poll_pending_list)) { + struct p9_conn *conn = list_first_entry(&p9_poll_pending_list, + struct p9_conn, + poll_pending_link); + list_del_init(&conn->poll_pending_link); + spin_unlock_irqrestore(&p9_poll_lock, flags); - list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) { - p9_poll_mux(m); - } + p9_poll_mux(conn); - P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n"); - schedule_timeout(SCHED_TIMEOUT * HZ); + spin_lock_irqsave(&p9_poll_lock, flags); } + spin_unlock_irqrestore(&p9_poll_lock, flags); + set_current_state(TASK_INTERRUPTIBLE); + if (list_empty(&p9_poll_pending_list)) { + P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n"); + schedule(); + } __set_current_state(TASK_RUNNING); + + if (!kthread_should_stop()) + goto repeat; + P9_DPRINTK(P9_DEBUG_MUX, "finish\n"); return 0; } @@ -1602,17 +1519,19 @@ static struct p9_trans_module p9_fd_trans = { int p9_trans_fd_init(void) { - int i; - - for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) - p9_mux_poll_tasks[i].task = NULL; - p9_mux_wq = create_workqueue("v9fs"); if (!p9_mux_wq) { printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n"); return -ENOMEM; } + p9_poll_task = kthread_run(p9_poll_proc, NULL, "v9fs-poll"); + if (IS_ERR(p9_poll_task)) { + destroy_workqueue(p9_mux_wq); + printk(KERN_WARNING "v9fs: mux: creating poll task failed\n"); + return PTR_ERR(p9_poll_task); + } + v9fs_register_trans(&p9_tcp_trans); v9fs_register_trans(&p9_unix_trans); v9fs_register_trans(&p9_fd_trans); @@ -1622,6 +1541,7 @@ int p9_trans_fd_init(void) void p9_trans_fd_exit(void) { + kthread_stop(p9_poll_task); v9fs_unregister_trans(&p9_tcp_trans); v9fs_unregister_trans(&p9_unix_trans); v9fs_unregister_trans(&p9_fd_trans); -- cgit v1.2.3 From 8b81ef589ad1483dd977ef47fe00d4ce4d91a0ab Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:25 -0500 Subject: 9p: consolidate transport structure Right now there is a transport module structure which provides per-transport type functions and data and a transport structure which contains per-instance public data as well as function pointers to instance specific functions. This patch moves public transport visible instance data to the client structure (which in some cases had duplicate data) and consolidates the functions into the transport module structure. Signed-off-by: Eric Van Hensbergen --- fs/9p/v9fs.c | 2 +- include/net/9p/client.h | 19 ++++- include/net/9p/transport.h | 55 ++---------- net/9p/client.c | 21 ++--- net/9p/mod.c | 1 + net/9p/trans_fd.c | 205 ++++++++++++++++++++------------------------- net/9p/trans_virtio.c | 50 +++++------ 7 files changed, 146 insertions(+), 207 deletions(-) (limited to 'net/9p/trans_fd.c') diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index c061c3f18e7c..b6b85cf01e0d 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -30,8 +30,8 @@ #include #include #include -#include #include +#include #include "v9fs.h" #include "v9fs_vfs.h" diff --git a/include/net/9p/client.h b/include/net/9p/client.h index c936dd14de41..c35fb548e7cf 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -26,6 +26,22 @@ #ifndef NET_9P_CLIENT_H #define NET_9P_CLIENT_H +/** + * enum p9_trans_status - different states of underlying transports + * @Connected: transport is connected and healthy + * @Disconnected: transport has been disconnected + * @Hung: transport is connected by wedged + * + * This enumeration details the various states a transport + * instatiation can be in. + */ + +enum p9_trans_status { + Connected, + Disconnected, + Hung, +}; + /** * struct p9_client - per client instance state * @lock: protect @fidlist @@ -48,7 +64,8 @@ struct p9_client { int msize; unsigned char dotu; struct p9_trans_module *trans_mod; - struct p9_trans *trans; + enum p9_trans_status status; + void *trans; struct p9_conn *conn; struct p9_idpool *fidpool; diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h index 3ca737120a90..3e0f2f6beba2 100644 --- a/include/net/9p/transport.h +++ b/include/net/9p/transport.h @@ -26,52 +26,6 @@ #ifndef NET_9P_TRANSPORT_H #define NET_9P_TRANSPORT_H -#include - -/** - * enum p9_trans_status - different states of underlying transports - * @Connected: transport is connected and healthy - * @Disconnected: transport has been disconnected - * @Hung: transport is connected by wedged - * - * This enumeration details the various states a transport - * instatiation can be in. - */ - -enum p9_trans_status { - Connected, - Disconnected, - Hung, -}; - -/** - * struct p9_trans - per-transport state and API - * @status: transport &p9_trans_status - * @msize: negotiated maximum packet size (duplicate from client) - * @extended: negotiated protocol extensions (duplicate from client) - * @priv: transport private data - * @close: member function to disconnect and close the transport - * @rpc: member function to issue a request to the transport - * - * This is the basic API for a transport instance. It is used as - * a handle by the client to issue requests. This interface is currently - * in flux during reorganization. - * - * Bugs: there is lots of duplicated data here and its not clear that - * the member functions need to be per-instance versus per transport - * module. - */ - -struct p9_trans { - enum p9_trans_status status; - int msize; - unsigned char extended; - void *priv; - void (*close) (struct p9_trans *); - int (*rpc) (struct p9_trans *t, struct p9_fcall *tc, - struct p9_fcall **rc); -}; - /** * struct p9_trans_module - transport module interface * @list: used to maintain a list of currently available transports @@ -79,12 +33,14 @@ struct p9_trans { * @maxsize: transport provided maximum packet size * @def: set if this transport should be considered the default * @create: member function to create a new connection on this transport + * @close: member function to disconnect and close the transport + * @rpc: member function to issue a request to the transport * * This is the basic API for a transport module which is registered by the * transport module with the 9P core network module and used by the client * to instantiate a new connection on a transport. * - * Bugs: the transport module list isn't protected. + * BUGS: the transport module list isn't protected. */ struct p9_trans_module { @@ -92,8 +48,11 @@ struct p9_trans_module { char *name; /* name of transport */ int maxsize; /* max message size of transport */ int def; /* this transport should be default */ - struct p9_trans * (*create)(const char *, char *, int, unsigned char); struct module *owner; + int (*create)(struct p9_client *, const char *, char *); + void (*close) (struct p9_client *); + int (*rpc) (struct p9_client *t, struct p9_fcall *tc, + struct p9_fcall **rc); }; void v9fs_register_trans(struct p9_trans_module *m); diff --git a/net/9p/client.c b/net/9p/client.c index e053e06028a5..f1a52a7ed724 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -33,8 +33,8 @@ #include #include #include -#include #include +#include static struct p9_fid *p9_fid_create(struct p9_client *clnt); static void p9_fid_destroy(struct p9_fid *fid); @@ -136,7 +136,7 @@ int p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) { - return c->trans->rpc(c->trans, tc, rc); + return c->trans_mod->rpc(c, tc, rc); } struct p9_client *p9_client_create(const char *dev_name, char *options) @@ -179,13 +179,9 @@ struct p9_client *p9_client_create(const char *dev_name, char *options) clnt, clnt->trans_mod, clnt->msize, clnt->dotu); - clnt->trans = clnt->trans_mod->create(dev_name, options, clnt->msize, - clnt->dotu); - if (IS_ERR(clnt->trans)) { - err = PTR_ERR(clnt->trans); - clnt->trans = NULL; + err = clnt->trans_mod->create(clnt, dev_name, options); + if (err) goto error; - } if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize) clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ; @@ -233,11 +229,8 @@ void p9_client_destroy(struct p9_client *clnt) P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); - if (clnt->trans) { - clnt->trans->close(clnt->trans); - kfree(clnt->trans); - clnt->trans = NULL; - } + if (clnt->trans_mod) + clnt->trans_mod->close(clnt); v9fs_put_trans(clnt->trans_mod); @@ -254,7 +247,7 @@ EXPORT_SYMBOL(p9_client_destroy); void p9_client_disconnect(struct p9_client *clnt) { P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); - clnt->trans->status = Disconnected; + clnt->status = Disconnected; } EXPORT_SYMBOL(p9_client_disconnect); diff --git a/net/9p/mod.c b/net/9p/mod.c index 1084feb24cb0..cf8a4128cd5c 100644 --- a/net/9p/mod.c +++ b/net/9p/mod.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index f84592345573..d09389f08382 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #define P9_PORT 564 @@ -146,7 +147,7 @@ struct p9_poll_wait { * @mux_list: list link for mux to manage multiple connections (?) * @msize: maximum size for connection (dup) * @extended: 9p2000.u flag (dup) - * @trans: reference to transport instance for this connection + * @client: reference to client instance for this connection * @tagpool: id accounting for transactions * @err: error state * @req_list: accounting for requests which have been sent @@ -171,7 +172,7 @@ struct p9_conn { struct list_head mux_list; int msize; unsigned char extended; - struct p9_trans *trans; + struct p9_client *client; struct p9_idpool *tagpool; int err; struct list_head req_list; @@ -214,8 +215,8 @@ static void p9_read_work(struct work_struct *work); static void p9_write_work(struct work_struct *work); static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p); -static int p9_fd_write(struct p9_trans *trans, void *v, int len); -static int p9_fd_read(struct p9_trans *trans, void *v, int len); +static int p9_fd_write(struct p9_client *client, void *v, int len); +static int p9_fd_read(struct p9_client *client, void *v, int len); static DEFINE_SPINLOCK(p9_poll_lock); static LIST_HEAD(p9_poll_pending_list); @@ -223,7 +224,7 @@ static struct workqueue_struct *p9_mux_wq; static struct task_struct *p9_poll_task; static void p9_conn_destroy(struct p9_conn *); -static unsigned int p9_fd_poll(struct p9_trans *trans, +static unsigned int p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt); #ifdef P9_NONBLOCK @@ -271,27 +272,26 @@ static void p9_mux_poll_stop(struct p9_conn *m) /** * p9_conn_create - allocate and initialize the per-session mux data - * @trans: transport structure + * @client: client instance * * Note: Creates the polling task if this is the first session. */ -static struct p9_conn *p9_conn_create(struct p9_trans *trans) +static struct p9_conn *p9_conn_create(struct p9_client *client) { int i, n; struct p9_conn *m; - P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans, - trans->msize); + P9_DPRINTK(P9_DEBUG_MUX, "client %p msize %d\n", client, client->msize); m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL); if (!m) return ERR_PTR(-ENOMEM); spin_lock_init(&m->lock); INIT_LIST_HEAD(&m->mux_list); - m->msize = trans->msize; - m->extended = trans->extended; - m->trans = trans; + m->msize = client->msize; + m->extended = client->dotu; + m->client = client; m->tagpool = p9_idpool_create(); if (IS_ERR(m->tagpool)) { kfree(m); @@ -305,7 +305,7 @@ static struct p9_conn *p9_conn_create(struct p9_trans *trans) INIT_LIST_HEAD(&m->poll_pending_link); init_poll_funcptr(&m->pt, p9_pollwait); - n = p9_fd_poll(trans, &m->pt); + n = p9_fd_poll(client, &m->pt); if (n & POLLIN) { P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); set_bit(Rpending, &m->wsched); @@ -345,7 +345,7 @@ static void p9_conn_destroy(struct p9_conn *m) p9_conn_cancel(m, -ECONNRESET); - m->trans = NULL; + m->client = NULL; p9_idpool_destroy(m->tagpool); kfree(m); } @@ -420,7 +420,7 @@ static void p9_poll_mux(struct p9_conn *m) if (m->err < 0) return; - n = p9_fd_poll(m->trans, NULL); + n = p9_fd_poll(m->client, NULL); if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n); if (n >= 0) @@ -533,7 +533,7 @@ again: P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos, m->wsize); clear_bit(Wpending, &m->wsched); - err = p9_fd_write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos); + err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos); P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err); if (err == -EAGAIN) { clear_bit(Wworksched, &m->wsched); @@ -555,7 +555,7 @@ again: if (test_and_clear_bit(Wpending, &m->wsched)) n = POLLOUT; else - n = p9_fd_poll(m->trans, NULL); + n = p9_fd_poll(m->client, NULL); if (n & POLLOUT) { P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); @@ -640,7 +640,7 @@ static void p9_read_work(struct work_struct *work) } clear_bit(Rpending, &m->wsched); - err = p9_fd_read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos); + err = p9_fd_read(m->client, m->rbuf + m->rpos, m->msize - m->rpos); P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err); if (err == -EAGAIN) { clear_bit(Rworksched, &m->wsched); @@ -735,7 +735,7 @@ static void p9_read_work(struct work_struct *work) if (test_and_clear_bit(Rpending, &m->wsched)) n = POLLIN; else - n = p9_fd_poll(m->trans, NULL); + n = p9_fd_poll(m->client, NULL); if (n & POLLIN) { P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m); @@ -819,7 +819,7 @@ static struct p9_req *p9_send_request(struct p9_conn *m, if (test_and_clear_bit(Wpending, &m->wsched)) n = POLLOUT; else - n = p9_fd_poll(m->trans, NULL); + n = p9_fd_poll(m->client, NULL); if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched)) queue_work(p9_mux_wq, &m->wq); @@ -933,16 +933,16 @@ p9_conn_rpc_cb(struct p9_req *req, void *a) /** * p9_fd_rpc- sends 9P request and waits until a response is available. * The function can be interrupted. - * @t: transport data + * @client: client instance * @tc: request to be sent * @rc: pointer where a pointer to the response is stored * */ int -p9_fd_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc) +p9_fd_rpc(struct p9_client *client, struct p9_fcall *tc, struct p9_fcall **rc) { - struct p9_trans_fd *p = t->priv; + struct p9_trans_fd *p = client->trans; struct p9_conn *m = p->conn; int err, sigpending; unsigned long flags; @@ -975,7 +975,7 @@ p9_fd_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc) if (r.err < 0) err = r.err; - if (err == -ERESTARTSYS && m->trans->status == Connected + if (err == -ERESTARTSYS && client->status == Connected && m->err == 0) { if (p9_mux_flush_request(m, req)) { /* wait until we get response of the flush message */ @@ -984,7 +984,7 @@ p9_fd_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc) err = wait_event_interruptible(r.wqueue, r.rcall || r.err); } while (!r.rcall && !r.err && err == -ERESTARTSYS && - m->trans->status == Connected && !m->err); + client->status == Connected && !m->err); err = -ERESTARTSYS; } @@ -1133,7 +1133,7 @@ static int parse_opts(char *params, struct p9_fd_opts *opts) return 0; } -static int p9_fd_open(struct p9_trans *trans, int rfd, int wfd) +static int p9_fd_open(struct p9_client *client, int rfd, int wfd) { struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd), GFP_KERNEL); @@ -1151,13 +1151,13 @@ static int p9_fd_open(struct p9_trans *trans, int rfd, int wfd) return -EIO; } - trans->priv = ts; - trans->status = Connected; + client->trans = ts; + client->status = Connected; return 0; } -static int p9_socket_open(struct p9_trans *trans, struct socket *csocket) +static int p9_socket_open(struct p9_client *client, struct socket *csocket) { int fd, ret; @@ -1168,33 +1168,33 @@ static int p9_socket_open(struct p9_trans *trans, struct socket *csocket) return fd; } - ret = p9_fd_open(trans, fd, fd); + ret = p9_fd_open(client, fd, fd); if (ret < 0) { P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n"); sockfd_put(csocket); return ret; } - ((struct p9_trans_fd *)trans->priv)->rd->f_flags |= O_NONBLOCK; + ((struct p9_trans_fd *)client->trans)->rd->f_flags |= O_NONBLOCK; return 0; } /** * p9_fd_read- read from a fd - * @trans: transport instance state + * @client: client instance * @v: buffer to receive data into * @len: size of receive buffer * */ -static int p9_fd_read(struct p9_trans *trans, void *v, int len) +static int p9_fd_read(struct p9_client *client, void *v, int len) { int ret; struct p9_trans_fd *ts = NULL; - if (trans && trans->status != Disconnected) - ts = trans->priv; + if (client && client->status != Disconnected) + ts = client->trans; if (!ts) return -EREMOTEIO; @@ -1204,26 +1204,26 @@ static int p9_fd_read(struct p9_trans *trans, void *v, int len) ret = kernel_read(ts->rd, ts->rd->f_pos, v, len); if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) - trans->status = Disconnected; + client->status = Disconnected; return ret; } /** * p9_fd_write - write to a socket - * @trans: transport instance state + * @client: client instance * @v: buffer to send data from * @len: size of send buffer * */ -static int p9_fd_write(struct p9_trans *trans, void *v, int len) +static int p9_fd_write(struct p9_client *client, void *v, int len) { int ret; mm_segment_t oldfs; struct p9_trans_fd *ts = NULL; - if (trans && trans->status != Disconnected) - ts = trans->priv; + if (client && client->status != Disconnected) + ts = client->trans; if (!ts) return -EREMOTEIO; @@ -1238,18 +1238,18 @@ static int p9_fd_write(struct p9_trans *trans, void *v, int len) set_fs(oldfs); if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) - trans->status = Disconnected; + client->status = Disconnected; return ret; } static unsigned int -p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt) +p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt) { int ret, n; struct p9_trans_fd *ts = NULL; - if (trans && trans->status == Connected) - ts = trans->priv; + if (client && client->status == Connected) + ts = client->trans; if (!ts) return -EREMOTEIO; @@ -1275,30 +1275,31 @@ p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt) } /** - * p9_fd_close - shutdown socket - * @trans: private socket structure + * p9_fd_close - shutdown file descriptor transport + * @client: client instance * */ -static void p9_fd_close(struct p9_trans *trans) +static void p9_fd_close(struct p9_client *client) { struct p9_trans_fd *ts; - if (!trans) + if (!client) return; - ts = xchg(&trans->priv, NULL); - + ts = client->trans; if (!ts) return; + client->status = Disconnected; + p9_conn_destroy(ts->conn); - trans->status = Disconnected; if (ts->rd) fput(ts->rd); if (ts->wr) fput(ts->wr); + kfree(ts); } @@ -1319,31 +1320,23 @@ static inline int valid_ipaddr4(const char *buf) return 0; } -static struct p9_trans * -p9_trans_create_tcp(const char *addr, char *args, int msize, unsigned char dotu) +static int +p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args) { int err; - struct p9_trans *trans; struct socket *csocket; struct sockaddr_in sin_server; struct p9_fd_opts opts; - struct p9_trans_fd *p; + struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */ err = parse_opts(args, &opts); if (err < 0) - return ERR_PTR(err); + return err; if (valid_ipaddr4(addr) < 0) - return ERR_PTR(-EINVAL); + return -EINVAL; csocket = NULL; - trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); - if (!trans) - return ERR_PTR(-ENOMEM); - trans->msize = msize; - trans->extended = dotu; - trans->rpc = p9_fd_rpc; - trans->close = p9_fd_close; sin_server.sin_family = AF_INET; sin_server.sin_addr.s_addr = in_aton(addr); @@ -1366,45 +1359,38 @@ p9_trans_create_tcp(const char *addr, char *args, int msize, unsigned char dotu) goto error; } - err = p9_socket_open(trans, csocket); + err = p9_socket_open(client, csocket); if (err < 0) goto error; - p = (struct p9_trans_fd *) trans->priv; - p->conn = p9_conn_create(trans); + p = (struct p9_trans_fd *) client->trans; + p->conn = p9_conn_create(client); if (IS_ERR(p->conn)) { err = PTR_ERR(p->conn); p->conn = NULL; goto error; } - return trans; + return 0; error: if (csocket) sock_release(csocket); - kfree(trans); - return ERR_PTR(err); + kfree(p); + + return err; } -static struct p9_trans * -p9_trans_create_unix(const char *addr, char *args, int msize, - unsigned char dotu) +static int +p9_fd_create_unix(struct p9_client *client, const char *addr, char *args) { int err; struct socket *csocket; struct sockaddr_un sun_server; - struct p9_trans *trans; - struct p9_trans_fd *p; + struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */ csocket = NULL; - trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); - if (!trans) - return ERR_PTR(-ENOMEM); - - trans->rpc = p9_fd_rpc; - trans->close = p9_fd_close; if (strlen(addr) > UNIX_PATH_MAX) { P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n", @@ -1425,79 +1411,68 @@ p9_trans_create_unix(const char *addr, char *args, int msize, goto error; } - err = p9_socket_open(trans, csocket); + err = p9_socket_open(client, csocket); if (err < 0) goto error; - trans->msize = msize; - trans->extended = dotu; - p = (struct p9_trans_fd *) trans->priv; - p->conn = p9_conn_create(trans); + p = (struct p9_trans_fd *) client->trans; + p->conn = p9_conn_create(client); if (IS_ERR(p->conn)) { err = PTR_ERR(p->conn); p->conn = NULL; goto error; } - return trans; + return 0; error: if (csocket) sock_release(csocket); - kfree(trans); - return ERR_PTR(err); + kfree(p); + return err; } -static struct p9_trans * -p9_trans_create_fd(const char *name, char *args, int msize, - unsigned char extended) +static int +p9_fd_create(struct p9_client *client, const char *addr, char *args) { int err; - struct p9_trans *trans; struct p9_fd_opts opts; - struct p9_trans_fd *p; + struct p9_trans_fd *p = NULL; /* this get allocated in p9_fd_open */ parse_opts(args, &opts); if (opts.rfd == ~0 || opts.wfd == ~0) { printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n"); - return ERR_PTR(-ENOPROTOOPT); + return -ENOPROTOOPT; } - trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); - if (!trans) - return ERR_PTR(-ENOMEM); - - trans->rpc = p9_fd_rpc; - trans->close = p9_fd_close; - - err = p9_fd_open(trans, opts.rfd, opts.wfd); + err = p9_fd_open(client, opts.rfd, opts.wfd); if (err < 0) goto error; - trans->msize = msize; - trans->extended = extended; - p = (struct p9_trans_fd *) trans->priv; - p->conn = p9_conn_create(trans); + p = (struct p9_trans_fd *) client->trans; + p->conn = p9_conn_create(client); if (IS_ERR(p->conn)) { err = PTR_ERR(p->conn); p->conn = NULL; goto error; } - return trans; + return 0; error: - kfree(trans); - return ERR_PTR(err); + kfree(p); + return err; } static struct p9_trans_module p9_tcp_trans = { .name = "tcp", .maxsize = MAX_SOCK_BUF, .def = 1, - .create = p9_trans_create_tcp, + .create = p9_fd_create_tcp, + .close = p9_fd_close, + .rpc = p9_fd_rpc, .owner = THIS_MODULE, }; @@ -1505,7 +1480,9 @@ static struct p9_trans_module p9_unix_trans = { .name = "unix", .maxsize = MAX_SOCK_BUF, .def = 0, - .create = p9_trans_create_unix, + .create = p9_fd_create_unix, + .close = p9_fd_close, + .rpc = p9_fd_rpc, .owner = THIS_MODULE, }; @@ -1513,7 +1490,9 @@ static struct p9_trans_module p9_fd_trans = { .name = "fd", .maxsize = MAX_SOCK_BUF, .def = 0, - .create = p9_trans_create_fd, + .create = p9_fd_create, + .close = p9_fd_close, + .rpc = p9_fd_rpc, .owner = THIS_MODULE, }; diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 94912e077a55..72493f04a76d 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -55,7 +56,6 @@ static int chan_index; #define P9_INIT_MAXTAG 16 - /** * enum p9_req_status_t - virtio request status * @REQ_STATUS_IDLE: request slot unused @@ -197,9 +197,9 @@ static unsigned int rest_of_page(void *data) * */ -static void p9_virtio_close(struct p9_trans *trans) +static void p9_virtio_close(struct p9_client *client) { - struct virtio_chan *chan = trans->priv; + struct virtio_chan *chan = client->trans; int count; unsigned long flags; @@ -215,7 +215,7 @@ static void p9_virtio_close(struct p9_trans *trans) chan->inuse = false; mutex_unlock(&virtio_9p_lock); - kfree(trans); + client->trans = NULL; } /** @@ -292,17 +292,17 @@ pack_sg_list(struct scatterlist *sg, int start, int limit, char *data, */ static int -p9_virtio_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc) +p9_virtio_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) { int in, out; int n, err, size; - struct virtio_chan *chan = t->priv; + struct virtio_chan *chan = c->trans; char *rdata; struct p9_req_t *req; unsigned long flags; if (*rc == NULL) { - *rc = kmalloc(sizeof(struct p9_fcall) + t->msize, GFP_KERNEL); + *rc = kmalloc(sizeof(struct p9_fcall) + c->msize, GFP_KERNEL); if (!*rc) return -ENOMEM; } @@ -325,7 +325,7 @@ p9_virtio_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc) P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio rpc tag %d\n", n); out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, tc->sdata, tc->size); - in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, t->msize); + in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, c->msize); req->status = REQ_STATUS_SENT; @@ -341,7 +341,7 @@ p9_virtio_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc) size = le32_to_cpu(*(__le32 *) rdata); - err = p9_deserialize_fcall(rdata, size, *rc, t->extended); + err = p9_deserialize_fcall(rdata, size, *rc, c->dotu); if (err < 0) { P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio rpc deserialize returned %d\n", err); @@ -352,8 +352,8 @@ p9_virtio_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc) if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { char buf[150]; - p9_printfcall(buf, sizeof(buf), *rc, t->extended); - printk(KERN_NOTICE ">>> %p %s\n", t, buf); + p9_printfcall(buf, sizeof(buf), *rc, c->dotu); + printk(KERN_NOTICE ">>> %p %s\n", c, buf); } #endif @@ -422,10 +422,9 @@ fail: /** * p9_virtio_create - allocate a new virtio channel + * @client: client instance invoking this transport * @devname: string identifying the channel to connect to (unused) * @args: args passed from sys_mount() for per-transport options (unused) - * @msize: requested maximum packet size - * @extended: 9p2000.u enabled flag * * This sets up a transport channel for 9p communication. Right now * we only match the first available channel, but eventually we couldlook up @@ -441,11 +440,9 @@ fail: * */ -static struct p9_trans * -p9_virtio_create(const char *devname, char *args, int msize, - unsigned char extended) +static int +p9_virtio_create(struct p9_client *client, const char *devname, char *args) { - struct p9_trans *trans; struct virtio_chan *chan = channels; int index = 0; @@ -463,30 +460,21 @@ p9_virtio_create(const char *devname, char *args, int msize, if (index >= MAX_9P_CHAN) { printk(KERN_ERR "9p: no channels available\n"); - return ERR_PTR(-ENODEV); + return -ENODEV; } chan->tagpool = p9_idpool_create(); if (IS_ERR(chan->tagpool)) { printk(KERN_ERR "9p: couldn't allocate tagpool\n"); - return ERR_PTR(-ENOMEM); + return -ENOMEM; } p9_idpool_get(chan->tagpool); /* reserve tag 0 */ chan->max_tag = 0; chan->reqs = NULL; - trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); - if (!trans) { - printk(KERN_ERR "9p: couldn't allocate transport\n"); - return ERR_PTR(-ENOMEM); - } - trans->extended = extended; - trans->msize = msize; - trans->close = p9_virtio_close; - trans->rpc = p9_virtio_rpc; - trans->priv = chan; + client->trans = (void *)chan; - return trans; + return 0; } /** @@ -526,6 +514,8 @@ static struct virtio_driver p9_virtio_drv = { static struct p9_trans_module p9_virtio_trans = { .name = "virtio", .create = p9_virtio_create, + .close = p9_virtio_close, + .rpc = p9_virtio_rpc, .maxsize = PAGE_SIZE*16, .def = 0, .owner = THIS_MODULE, -- cgit v1.2.3 From bead27f0a87f4055f6a0fd69ded9eacced485618 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:24 -0500 Subject: 9p: remove duplicate client state Now that we are passing client state into the transport modules, remove duplicate state which is present in transport private structures. Signed-off-by: Eric Van Hensbergen --- net/9p/trans_fd.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) (limited to 'net/9p/trans_fd.c') diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index d09389f08382..bc5b6965981b 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -145,8 +145,6 @@ struct p9_poll_wait { * struct p9_conn - fd mux connection state information * @lock: protects mux_list (?) * @mux_list: list link for mux to manage multiple connections (?) - * @msize: maximum size for connection (dup) - * @extended: 9p2000.u flag (dup) * @client: reference to client instance for this connection * @tagpool: id accounting for transactions * @err: error state @@ -170,8 +168,6 @@ struct p9_poll_wait { struct p9_conn { spinlock_t lock; /* protect lock structure */ struct list_head mux_list; - int msize; - unsigned char extended; struct p9_client *client; struct p9_idpool *tagpool; int err; @@ -289,8 +285,6 @@ static struct p9_conn *p9_conn_create(struct p9_client *client) spin_lock_init(&m->lock); INIT_LIST_HEAD(&m->mux_list); - m->msize = client->msize; - m->extended = client->dotu; m->client = client; m->tagpool = p9_idpool_create(); if (IS_ERR(m->tagpool)) { @@ -584,7 +578,7 @@ static void process_request(struct p9_conn *m, struct p9_req *req) P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len, ename->str); - if (m->extended) + if (m->client->dotu) req->err = -ecode; if (!req->err) { @@ -629,7 +623,8 @@ static void p9_read_work(struct work_struct *work) if (!m->rcall) { m->rcall = - kmalloc(sizeof(struct p9_fcall) + m->msize, GFP_KERNEL); + kmalloc(sizeof(struct p9_fcall) + m->client->msize, + GFP_KERNEL); if (!m->rcall) { err = -ENOMEM; goto error; @@ -640,7 +635,8 @@ static void p9_read_work(struct work_struct *work) } clear_bit(Rpending, &m->wsched); - err = p9_fd_read(m->client, m->rbuf + m->rpos, m->msize - m->rpos); + err = p9_fd_read(m->client, m->rbuf + m->rpos, + m->client->msize - m->rpos); P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err); if (err == -EAGAIN) { clear_bit(Rworksched, &m->wsched); @@ -653,7 +649,7 @@ static void p9_read_work(struct work_struct *work) m->rpos += err; while (m->rpos > 4) { n = le32_to_cpu(*(__le32 *) m->rbuf); - if (n >= m->msize) { + if (n >= m->client->msize) { P9_DPRINTK(P9_DEBUG_ERROR, "requested packet size too big: %d\n", n); err = -EIO; @@ -664,7 +660,7 @@ static void p9_read_work(struct work_struct *work) break; err = - p9_deserialize_fcall(m->rbuf, n, m->rcall, m->extended); + p9_deserialize_fcall(m->rbuf, n, m->rcall, m->client->dotu); if (err < 0) goto error; @@ -673,7 +669,7 @@ static void p9_read_work(struct work_struct *work) char buf[150]; p9_printfcall(buf, sizeof(buf), m->rcall, - m->extended); + m->client->dotu); printk(KERN_NOTICE ">>> %p %s\n", m, buf); } #endif @@ -681,8 +677,8 @@ static void p9_read_work(struct work_struct *work) rcall = m->rcall; rbuf = m->rbuf; if (m->rpos > n) { - m->rcall = kmalloc(sizeof(struct p9_fcall) + m->msize, - GFP_KERNEL); + m->rcall = kmalloc(sizeof(struct p9_fcall) + + m->client->msize, GFP_KERNEL); if (!m->rcall) { err = -ENOMEM; goto error; @@ -798,7 +794,7 @@ static struct p9_req *p9_send_request(struct p9_conn *m, if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { char buf[150]; - p9_printfcall(buf, sizeof(buf), tc, m->extended); + p9_printfcall(buf, sizeof(buf), tc, m->client->dotu); printk(KERN_NOTICE "<<< %p %s\n", m, buf); } #endif -- cgit v1.2.3 From 5503ac565998837350f3ee1cc344c36143ea2386 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:24 -0500 Subject: 9p: remove unnecessary prototypes Cleanup files by reordering functions in order to remove need for unnecessary function prototypes. There are no code changes here, just functions being moved around and prototypes being eliminated. Signed-off-by: Eric Van Hensbergen --- net/9p/client.c | 183 ++++++----- net/9p/trans_fd.c | 896 ++++++++++++++++++++++++++---------------------------- 2 files changed, 513 insertions(+), 566 deletions(-) (limited to 'net/9p/trans_fd.c') diff --git a/net/9p/client.c b/net/9p/client.c index f1a52a7ed724..712d4f336adc 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -36,10 +36,6 @@ #include #include -static struct p9_fid *p9_fid_create(struct p9_client *clnt); -static void p9_fid_destroy(struct p9_fid *fid); -static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu); - /* * Client Option Parsing (code inspired by NFS code) * - a little lazy - parse all client options @@ -124,6 +120,55 @@ static int parse_opts(char *opts, struct p9_client *clnt) return ret; } +static struct p9_fid *p9_fid_create(struct p9_client *clnt) +{ + int err; + struct p9_fid *fid; + + P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); + fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL); + if (!fid) + return ERR_PTR(-ENOMEM); + + fid->fid = p9_idpool_get(clnt->fidpool); + if (fid->fid < 0) { + err = -ENOSPC; + goto error; + } + + memset(&fid->qid, 0, sizeof(struct p9_qid)); + fid->mode = -1; + fid->rdir_fpos = 0; + fid->rdir_pos = 0; + fid->rdir_fcall = NULL; + fid->uid = current->fsuid; + fid->clnt = clnt; + fid->aux = NULL; + + spin_lock(&clnt->lock); + list_add(&fid->flist, &clnt->fidlist); + spin_unlock(&clnt->lock); + + return fid; + +error: + kfree(fid); + return ERR_PTR(err); +} + +static void p9_fid_destroy(struct p9_fid *fid) +{ + struct p9_client *clnt; + + P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); + clnt = fid->clnt; + p9_idpool_put(fid->fid, clnt->fidpool); + spin_lock(&clnt->lock); + list_del(&fid->flist); + spin_unlock(&clnt->lock); + kfree(fid->rdir_fcall); + kfree(fid); +} /** * p9_client_rpc - sends 9P request and waits until a response is available. @@ -815,6 +860,46 @@ int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count) } EXPORT_SYMBOL(p9_client_readn); +static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu) +{ + int n; + char *p; + struct p9_stat *ret; + + n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len + + st->muid.len; + + if (dotu) + n += st->extension.len; + + ret = kmalloc(n, GFP_KERNEL); + if (!ret) + return ERR_PTR(-ENOMEM); + + memmove(ret, st, sizeof(struct p9_stat)); + p = ((char *) ret) + sizeof(struct p9_stat); + memmove(p, st->name.str, st->name.len); + ret->name.str = p; + p += st->name.len; + memmove(p, st->uid.str, st->uid.len); + ret->uid.str = p; + p += st->uid.len; + memmove(p, st->gid.str, st->gid.len); + ret->gid.str = p; + p += st->gid.len; + memmove(p, st->muid.str, st->muid.len); + ret->muid.str = p; + p += st->muid.len; + + if (dotu) { + memmove(p, st->extension.str, st->extension.len); + ret->extension.str = p; + p += st->extension.len; + } + + return ret; +} + struct p9_stat *p9_client_stat(struct p9_fid *fid) { int err; @@ -986,93 +1071,3 @@ error: return ERR_PTR(err); } EXPORT_SYMBOL(p9_client_dirread); - -static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu) -{ - int n; - char *p; - struct p9_stat *ret; - - n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len + - st->muid.len; - - if (dotu) - n += st->extension.len; - - ret = kmalloc(n, GFP_KERNEL); - if (!ret) - return ERR_PTR(-ENOMEM); - - memmove(ret, st, sizeof(struct p9_stat)); - p = ((char *) ret) + sizeof(struct p9_stat); - memmove(p, st->name.str, st->name.len); - ret->name.str = p; - p += st->name.len; - memmove(p, st->uid.str, st->uid.len); - ret->uid.str = p; - p += st->uid.len; - memmove(p, st->gid.str, st->gid.len); - ret->gid.str = p; - p += st->gid.len; - memmove(p, st->muid.str, st->muid.len); - ret->muid.str = p; - p += st->muid.len; - - if (dotu) { - memmove(p, st->extension.str, st->extension.len); - ret->extension.str = p; - p += st->extension.len; - } - - return ret; -} - -static struct p9_fid *p9_fid_create(struct p9_client *clnt) -{ - int err; - struct p9_fid *fid; - - P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); - fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL); - if (!fid) - return ERR_PTR(-ENOMEM); - - fid->fid = p9_idpool_get(clnt->fidpool); - if (fid->fid < 0) { - err = -ENOSPC; - goto error; - } - - memset(&fid->qid, 0, sizeof(struct p9_qid)); - fid->mode = -1; - fid->rdir_fpos = 0; - fid->rdir_pos = 0; - fid->rdir_fcall = NULL; - fid->uid = current->fsuid; - fid->clnt = clnt; - fid->aux = NULL; - - spin_lock(&clnt->lock); - list_add(&fid->flist, &clnt->fidlist); - spin_unlock(&clnt->lock); - - return fid; - -error: - kfree(fid); - return ERR_PTR(err); -} - -static void p9_fid_destroy(struct p9_fid *fid) -{ - struct p9_client *clnt; - - P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); - clnt = fid->clnt; - p9_idpool_put(fid->fid, clnt->fidpool); - spin_lock(&clnt->lock); - list_del(&fid->flist); - spin_unlock(&clnt->lock); - kfree(fid->rdir_fcall); - kfree(fid); -} diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index bc5b6965981b..334d39cc5ba3 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -61,7 +61,6 @@ struct p9_fd_opts { u16 port; }; - /** * struct p9_trans_fd - transport state * @rd: reference to file to read from @@ -206,30 +205,11 @@ struct p9_mux_rpc { wait_queue_head_t wqueue; }; -static int p9_poll_proc(void *); -static void p9_read_work(struct work_struct *work); -static void p9_write_work(struct work_struct *work); -static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, - poll_table *p); -static int p9_fd_write(struct p9_client *client, void *v, int len); -static int p9_fd_read(struct p9_client *client, void *v, int len); - static DEFINE_SPINLOCK(p9_poll_lock); static LIST_HEAD(p9_poll_pending_list); static struct workqueue_struct *p9_mux_wq; static struct task_struct *p9_poll_task; -static void p9_conn_destroy(struct p9_conn *); -static unsigned int p9_fd_poll(struct p9_client *client, - struct poll_table_struct *pt); - -#ifdef P9_NONBLOCK -static int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc, - p9_conn_req_callback cb, void *a); -#endif /* P9_NONBLOCK */ - -static void p9_conn_cancel(struct p9_conn *m, int err); - static u16 p9_mux_get_tag(struct p9_conn *m) { int tag; @@ -267,222 +247,314 @@ static void p9_mux_poll_stop(struct p9_conn *m) } /** - * p9_conn_create - allocate and initialize the per-session mux data - * @client: client instance + * p9_conn_cancel - cancel all pending requests with error + * @m: mux data + * @err: error code * - * Note: Creates the polling task if this is the first session. */ -static struct p9_conn *p9_conn_create(struct p9_client *client) +void p9_conn_cancel(struct p9_conn *m, int err) { - int i, n; - struct p9_conn *m; - - P9_DPRINTK(P9_DEBUG_MUX, "client %p msize %d\n", client, client->msize); - m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL); - if (!m) - return ERR_PTR(-ENOMEM); + struct p9_req *req, *rtmp; + LIST_HEAD(cancel_list); - spin_lock_init(&m->lock); - INIT_LIST_HEAD(&m->mux_list); - m->client = client; - m->tagpool = p9_idpool_create(); - if (IS_ERR(m->tagpool)) { - kfree(m); - return ERR_PTR(-ENOMEM); + P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err); + m->err = err; + spin_lock(&m->lock); + list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { + list_move(&req->req_list, &cancel_list); + } + list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { + list_move(&req->req_list, &cancel_list); } + spin_unlock(&m->lock); - INIT_LIST_HEAD(&m->req_list); - INIT_LIST_HEAD(&m->unsent_req_list); - INIT_WORK(&m->rq, p9_read_work); - INIT_WORK(&m->wq, p9_write_work); - INIT_LIST_HEAD(&m->poll_pending_link); - init_poll_funcptr(&m->pt, p9_pollwait); + list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { + list_del(&req->req_list); + if (!req->err) + req->err = err; - n = p9_fd_poll(client, &m->pt); - if (n & POLLIN) { - P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); - set_bit(Rpending, &m->wsched); + if (req->cb) + (*req->cb) (req, req->cba); + else + kfree(req->rcall); } +} - if (n & POLLOUT) { - P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); - set_bit(Wpending, &m->wsched); - } +static void process_request(struct p9_conn *m, struct p9_req *req) +{ + int ecode; + struct p9_str *ename; - for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { - if (IS_ERR(m->poll_wait[i].wait_addr)) { - p9_mux_poll_stop(m); - kfree(m); - /* return the error code */ - return (void *)m->poll_wait[i].wait_addr; + if (!req->err && req->rcall->id == P9_RERROR) { + ecode = req->rcall->params.rerror.errno; + ename = &req->rcall->params.rerror.error; + + P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len, + ename->str); + + if (m->client->dotu) + req->err = -ecode; + + if (!req->err) { + req->err = p9_errstr2errno(ename->str, ename->len); + + /* string match failed */ + if (!req->err) { + PRINT_FCALL_ERROR("unknown error", req->rcall); + req->err = -ESERVERFAULT; + } } + } else if (req->tcall && req->rcall->id != req->tcall->id + 1) { + P9_DPRINTK(P9_DEBUG_ERROR, + "fcall mismatch: expected %d, got %d\n", + req->tcall->id + 1, req->rcall->id); + if (!req->err) + req->err = -EIO; } - - return m; } -/** - * p9_mux_destroy - cancels all pending requests and frees mux resources - * @m: mux to destroy - * - */ - -static void p9_conn_destroy(struct p9_conn *m) +static unsigned int +p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt) { - P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m, - m->mux_list.prev, m->mux_list.next); + int ret, n; + struct p9_trans_fd *ts = NULL; - p9_mux_poll_stop(m); - cancel_work_sync(&m->rq); - cancel_work_sync(&m->wq); + if (client && client->status == Connected) + ts = client->trans; - p9_conn_cancel(m, -ECONNRESET); + if (!ts) + return -EREMOTEIO; - m->client = NULL; - p9_idpool_destroy(m->tagpool); - kfree(m); -} + if (!ts->rd->f_op || !ts->rd->f_op->poll) + return -EIO; -static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) -{ - struct p9_poll_wait *pwait = - container_of(wait, struct p9_poll_wait, wait); - struct p9_conn *m = pwait->conn; - unsigned long flags; - DECLARE_WAITQUEUE(dummy_wait, p9_poll_task); + if (!ts->wr->f_op || !ts->wr->f_op->poll) + return -EIO; - spin_lock_irqsave(&p9_poll_lock, flags); - if (list_empty(&m->poll_pending_link)) - list_add_tail(&m->poll_pending_link, &p9_poll_pending_list); - spin_unlock_irqrestore(&p9_poll_lock, flags); + ret = ts->rd->f_op->poll(ts->rd, pt); + if (ret < 0) + return ret; - /* perform the default wake up operation */ - return default_wake_function(&dummy_wait, mode, sync, key); + if (ts->rd != ts->wr) { + n = ts->wr->f_op->poll(ts->wr, pt); + if (n < 0) + return n; + ret = (ret & ~POLLOUT) | (n & ~POLLIN); + } + + return ret; } /** - * p9_pollwait - add poll task to the wait queue - * @filp: file pointer being polled - * @wait_address: wait_q to block on - * @p: poll state + * p9_fd_read- read from a fd + * @client: client instance + * @v: buffer to receive data into + * @len: size of receive buffer * - * called by files poll operation to add v9fs-poll task to files wait queue */ -static void -p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) +static int p9_fd_read(struct p9_client *client, void *v, int len) { - struct p9_conn *m = container_of(p, struct p9_conn, pt); - struct p9_poll_wait *pwait = NULL; - int i; + int ret; + struct p9_trans_fd *ts = NULL; - for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { - if (m->poll_wait[i].wait_addr == NULL) { - pwait = &m->poll_wait[i]; - break; - } - } + if (client && client->status != Disconnected) + ts = client->trans; - if (!pwait) { - P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n"); - return; - } + if (!ts) + return -EREMOTEIO; - if (!wait_address) { - P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n"); - pwait->wait_addr = ERR_PTR(-EIO); - return; - } + if (!(ts->rd->f_flags & O_NONBLOCK)) + P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n"); - pwait->conn = m; - pwait->wait_addr = wait_address; - init_waitqueue_func_entry(&pwait->wait, p9_pollwake); - add_wait_queue(wait_address, &pwait->wait); + ret = kernel_read(ts->rd, ts->rd->f_pos, v, len); + if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) + client->status = Disconnected; + return ret; } /** - * p9_poll_mux - polls a mux and schedules read or write works if necessary - * @m: connection to poll + * p9_read_work - called when there is some data to be read from a transport + * @work: container of work to be done * */ -static void p9_poll_mux(struct p9_conn *m) +static void p9_read_work(struct work_struct *work) { - int n; + int n, err; + struct p9_conn *m; + struct p9_req *req, *rptr, *rreq; + struct p9_fcall *rcall; + char *rbuf; + + m = container_of(work, struct p9_conn, rq); if (m->err < 0) return; - n = p9_fd_poll(m->client, NULL); - if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { - P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n); - if (n >= 0) - n = -ECONNRESET; - p9_conn_cancel(m, n); - } + rcall = NULL; + P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); - if (n & POLLIN) { - set_bit(Rpending, &m->wsched); - P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); - if (!test_and_set_bit(Rworksched, &m->wsched)) { - P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m); - queue_work(p9_mux_wq, &m->rq); + if (!m->rcall) { + m->rcall = + kmalloc(sizeof(struct p9_fcall) + m->client->msize, + GFP_KERNEL); + if (!m->rcall) { + err = -ENOMEM; + goto error; } + + m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall); + m->rpos = 0; } - if (n & POLLOUT) { - set_bit(Wpending, &m->wsched); - P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); - if ((m->wsize || !list_empty(&m->unsent_req_list)) - && !test_and_set_bit(Wworksched, &m->wsched)) { - P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); - queue_work(p9_mux_wq, &m->wq); - } + clear_bit(Rpending, &m->wsched); + err = p9_fd_read(m->client, m->rbuf + m->rpos, + m->client->msize - m->rpos); + P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err); + if (err == -EAGAIN) { + clear_bit(Rworksched, &m->wsched); + return; } -} -/** - * p9_poll_proc - poll worker thread - * @a: thread state and arguments - * - * polls all v9fs transports for new events and queues the appropriate - * work to the work queue + if (err <= 0) + goto error; + + m->rpos += err; + while (m->rpos > 4) { + n = le32_to_cpu(*(__le32 *) m->rbuf); + if (n >= m->client->msize) { + P9_DPRINTK(P9_DEBUG_ERROR, + "requested packet size too big: %d\n", n); + err = -EIO; + goto error; + } + + if (m->rpos < n) + break; + + err = + p9_deserialize_fcall(m->rbuf, n, m->rcall, m->client->dotu); + if (err < 0) + goto error; + +#ifdef CONFIG_NET_9P_DEBUG + if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { + char buf[150]; + + p9_printfcall(buf, sizeof(buf), m->rcall, + m->client->dotu); + printk(KERN_NOTICE ">>> %p %s\n", m, buf); + } +#endif + + rcall = m->rcall; + rbuf = m->rbuf; + if (m->rpos > n) { + m->rcall = kmalloc(sizeof(struct p9_fcall) + + m->client->msize, GFP_KERNEL); + if (!m->rcall) { + err = -ENOMEM; + goto error; + } + + m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall); + memmove(m->rbuf, rbuf + n, m->rpos - n); + m->rpos -= n; + } else { + m->rcall = NULL; + m->rbuf = NULL; + m->rpos = 0; + } + + P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, + rcall->id, rcall->tag); + + req = NULL; + spin_lock(&m->lock); + list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { + if (rreq->tag == rcall->tag) { + req = rreq; + if (req->flush != Flushing) + list_del(&req->req_list); + break; + } + } + spin_unlock(&m->lock); + + if (req) { + req->rcall = rcall; + process_request(m, req); + + if (req->flush != Flushing) { + if (req->cb) + (*req->cb) (req, req->cba); + else + kfree(req->rcall); + } + } else { + if (err >= 0 && rcall->id != P9_RFLUSH) + P9_DPRINTK(P9_DEBUG_ERROR, + "unexpected response mux %p id %d tag %d\n", + m, rcall->id, rcall->tag); + kfree(rcall); + } + } + + if (!list_empty(&m->req_list)) { + if (test_and_clear_bit(Rpending, &m->wsched)) + n = POLLIN; + else + n = p9_fd_poll(m->client, NULL); + + if (n & POLLIN) { + P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m); + queue_work(p9_mux_wq, &m->rq); + } else + clear_bit(Rworksched, &m->wsched); + } else + clear_bit(Rworksched, &m->wsched); + + return; + +error: + p9_conn_cancel(m, err); + clear_bit(Rworksched, &m->wsched); +} + +/** + * p9_fd_write - write to a socket + * @client: client instance + * @v: buffer to send data from + * @len: size of send buffer * */ -static int p9_poll_proc(void *a) +static int p9_fd_write(struct p9_client *client, void *v, int len) { - unsigned long flags; - - P9_DPRINTK(P9_DEBUG_MUX, "start %p\n", current); - repeat: - spin_lock_irqsave(&p9_poll_lock, flags); - while (!list_empty(&p9_poll_pending_list)) { - struct p9_conn *conn = list_first_entry(&p9_poll_pending_list, - struct p9_conn, - poll_pending_link); - list_del_init(&conn->poll_pending_link); - spin_unlock_irqrestore(&p9_poll_lock, flags); + int ret; + mm_segment_t oldfs; + struct p9_trans_fd *ts = NULL; - p9_poll_mux(conn); + if (client && client->status != Disconnected) + ts = client->trans; - spin_lock_irqsave(&p9_poll_lock, flags); - } - spin_unlock_irqrestore(&p9_poll_lock, flags); + if (!ts) + return -EREMOTEIO; - set_current_state(TASK_INTERRUPTIBLE); - if (list_empty(&p9_poll_pending_list)) { - P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n"); - schedule(); - } - __set_current_state(TASK_RUNNING); + if (!(ts->wr->f_flags & O_NONBLOCK)) + P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n"); - if (!kthread_should_stop()) - goto repeat; + 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); + set_fs(oldfs); - P9_DPRINTK(P9_DEBUG_MUX, "finish\n"); - return 0; + if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) + client->status = Disconnected; + return ret; } /** @@ -566,186 +638,158 @@ error: clear_bit(Wworksched, &m->wsched); } -static void process_request(struct p9_conn *m, struct p9_req *req) +static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) { - int ecode; - struct p9_str *ename; - - if (!req->err && req->rcall->id == P9_RERROR) { - ecode = req->rcall->params.rerror.errno; - ename = &req->rcall->params.rerror.error; - - P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len, - ename->str); - - if (m->client->dotu) - req->err = -ecode; + struct p9_poll_wait *pwait = + container_of(wait, struct p9_poll_wait, wait); + struct p9_conn *m = pwait->conn; + unsigned long flags; + DECLARE_WAITQUEUE(dummy_wait, p9_poll_task); - if (!req->err) { - req->err = p9_errstr2errno(ename->str, ename->len); + spin_lock_irqsave(&p9_poll_lock, flags); + if (list_empty(&m->poll_pending_link)) + list_add_tail(&m->poll_pending_link, &p9_poll_pending_list); + spin_unlock_irqrestore(&p9_poll_lock, flags); - /* string match failed */ - if (!req->err) { - PRINT_FCALL_ERROR("unknown error", req->rcall); - req->err = -ESERVERFAULT; - } - } - } else if (req->tcall && req->rcall->id != req->tcall->id + 1) { - P9_DPRINTK(P9_DEBUG_ERROR, - "fcall mismatch: expected %d, got %d\n", - req->tcall->id + 1, req->rcall->id); - if (!req->err) - req->err = -EIO; - } + /* perform the default wake up operation */ + return default_wake_function(&dummy_wait, mode, sync, key); } /** - * p9_read_work - called when there is some data to be read from a transport - * @work: container of work to be done + * p9_pollwait - add poll task to the wait queue + * @filp: file pointer being polled + * @wait_address: wait_q to block on + * @p: poll state * + * called by files poll operation to add v9fs-poll task to files wait queue */ -static void p9_read_work(struct work_struct *work) +static void +p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) { - int n, err; - struct p9_conn *m; - struct p9_req *req, *rptr, *rreq; - struct p9_fcall *rcall; - char *rbuf; - - m = container_of(work, struct p9_conn, rq); - - if (m->err < 0) - return; - - rcall = NULL; - P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); + struct p9_conn *m = container_of(p, struct p9_conn, pt); + struct p9_poll_wait *pwait = NULL; + int i; - if (!m->rcall) { - m->rcall = - kmalloc(sizeof(struct p9_fcall) + m->client->msize, - GFP_KERNEL); - if (!m->rcall) { - err = -ENOMEM; - goto error; + for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { + if (m->poll_wait[i].wait_addr == NULL) { + pwait = &m->poll_wait[i]; + break; } - - m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall); - m->rpos = 0; } - clear_bit(Rpending, &m->wsched); - err = p9_fd_read(m->client, m->rbuf + m->rpos, - m->client->msize - m->rpos); - P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err); - if (err == -EAGAIN) { - clear_bit(Rworksched, &m->wsched); + if (!pwait) { + P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n"); return; } - if (err <= 0) - goto error; - - m->rpos += err; - while (m->rpos > 4) { - n = le32_to_cpu(*(__le32 *) m->rbuf); - if (n >= m->client->msize) { - P9_DPRINTK(P9_DEBUG_ERROR, - "requested packet size too big: %d\n", n); - err = -EIO; - goto error; - } - - if (m->rpos < n) - break; - - err = - p9_deserialize_fcall(m->rbuf, n, m->rcall, m->client->dotu); - if (err < 0) - goto error; + if (!wait_address) { + P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n"); + pwait->wait_addr = ERR_PTR(-EIO); + return; + } -#ifdef CONFIG_NET_9P_DEBUG - if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { - char buf[150]; + pwait->conn = m; + pwait->wait_addr = wait_address; + init_waitqueue_func_entry(&pwait->wait, p9_pollwake); + add_wait_queue(wait_address, &pwait->wait); +} - p9_printfcall(buf, sizeof(buf), m->rcall, - m->client->dotu); - printk(KERN_NOTICE ">>> %p %s\n", m, buf); - } -#endif +/** + * p9_conn_create - allocate and initialize the per-session mux data + * @client: client instance + * + * Note: Creates the polling task if this is the first session. + */ - rcall = m->rcall; - rbuf = m->rbuf; - if (m->rpos > n) { - m->rcall = kmalloc(sizeof(struct p9_fcall) + - m->client->msize, GFP_KERNEL); - if (!m->rcall) { - err = -ENOMEM; - goto error; - } +static struct p9_conn *p9_conn_create(struct p9_client *client) +{ + int i, n; + struct p9_conn *m; - m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall); - memmove(m->rbuf, rbuf + n, m->rpos - n); - m->rpos -= n; - } else { - m->rcall = NULL; - m->rbuf = NULL; - m->rpos = 0; - } + P9_DPRINTK(P9_DEBUG_MUX, "client %p msize %d\n", client, client->msize); + m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL); + if (!m) + return ERR_PTR(-ENOMEM); - P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, - rcall->id, rcall->tag); + spin_lock_init(&m->lock); + INIT_LIST_HEAD(&m->mux_list); + m->client = client; + m->tagpool = p9_idpool_create(); + if (IS_ERR(m->tagpool)) { + kfree(m); + return ERR_PTR(-ENOMEM); + } - req = NULL; - spin_lock(&m->lock); - list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { - if (rreq->tag == rcall->tag) { - req = rreq; - if (req->flush != Flushing) - list_del(&req->req_list); - break; - } - } - spin_unlock(&m->lock); + INIT_LIST_HEAD(&m->req_list); + INIT_LIST_HEAD(&m->unsent_req_list); + INIT_WORK(&m->rq, p9_read_work); + INIT_WORK(&m->wq, p9_write_work); + INIT_LIST_HEAD(&m->poll_pending_link); + init_poll_funcptr(&m->pt, p9_pollwait); - if (req) { - req->rcall = rcall; - process_request(m, req); + n = p9_fd_poll(client, &m->pt); + if (n & POLLIN) { + P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); + set_bit(Rpending, &m->wsched); + } - if (req->flush != Flushing) { - if (req->cb) - (*req->cb) (req, req->cba); - else - kfree(req->rcall); - } - } else { - if (err >= 0 && rcall->id != P9_RFLUSH) - P9_DPRINTK(P9_DEBUG_ERROR, - "unexpected response mux %p id %d tag %d\n", - m, rcall->id, rcall->tag); - kfree(rcall); + if (n & POLLOUT) { + P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); + set_bit(Wpending, &m->wsched); + } + + for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { + if (IS_ERR(m->poll_wait[i].wait_addr)) { + p9_mux_poll_stop(m); + kfree(m); + /* return the error code */ + return (void *)m->poll_wait[i].wait_addr; } } - if (!list_empty(&m->req_list)) { - if (test_and_clear_bit(Rpending, &m->wsched)) - n = POLLIN; - else - n = p9_fd_poll(m->client, NULL); + return m; +} - if (n & POLLIN) { +/** + * p9_poll_mux - polls a mux and schedules read or write works if necessary + * @m: connection to poll + * + */ + +static void p9_poll_mux(struct p9_conn *m) +{ + int n; + + if (m->err < 0) + return; + + n = p9_fd_poll(m->client, NULL); + if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { + P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n); + if (n >= 0) + n = -ECONNRESET; + p9_conn_cancel(m, n); + } + + if (n & POLLIN) { + set_bit(Rpending, &m->wsched); + P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); + if (!test_and_set_bit(Rworksched, &m->wsched)) { P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m); queue_work(p9_mux_wq, &m->rq); - } else - clear_bit(Rworksched, &m->wsched); - } else - clear_bit(Rworksched, &m->wsched); - - return; + } + } -error: - p9_conn_cancel(m, err); - clear_bit(Rworksched, &m->wsched); + if (n & POLLOUT) { + set_bit(Wpending, &m->wsched); + P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); + if ((m->wsize || !list_empty(&m->unsent_req_list)) + && !test_and_set_bit(Wworksched, &m->wsched)) { + P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); + queue_work(p9_mux_wq, &m->wq); + } + } } /** @@ -1005,69 +1049,6 @@ p9_fd_rpc(struct p9_client *client, struct p9_fcall *tc, struct p9_fcall **rc) return err; } -#ifdef P9_NONBLOCK -/** - * p9_conn_rpcnb - sends 9P request without waiting for response. - * @m: mux data - * @tc: request to be sent - * @cb: callback function to be called when response arrives - * @a: value to pass to the callback function - * - */ - -int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc, - p9_conn_req_callback cb, void *a) -{ - int err; - struct p9_req *req; - - req = p9_send_request(m, tc, cb, a); - if (IS_ERR(req)) { - err = PTR_ERR(req); - P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err); - return PTR_ERR(req); - } - - P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag); - return 0; -} -#endif /* P9_NONBLOCK */ - -/** - * p9_conn_cancel - cancel all pending requests with error - * @m: mux data - * @err: error code - * - */ - -void p9_conn_cancel(struct p9_conn *m, int err) -{ - struct p9_req *req, *rtmp; - LIST_HEAD(cancel_list); - - P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err); - m->err = err; - spin_lock(&m->lock); - list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { - list_move(&req->req_list, &cancel_list); - } - list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { - list_move(&req->req_list, &cancel_list); - } - spin_unlock(&m->lock); - - list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { - list_del(&req->req_list); - if (!req->err) - req->err = err; - - if (req->cb) - (*req->cb) (req, req->cba); - else - kfree(req->rcall); - } -} - /** * parse_options - parse mount options into session structure * @options: options string passed from mount @@ -1177,97 +1158,25 @@ static int p9_socket_open(struct p9_client *client, struct socket *csocket) } /** - * p9_fd_read- read from a fd - * @client: client instance - * @v: buffer to receive data into - * @len: size of receive buffer - * - */ - -static int p9_fd_read(struct p9_client *client, void *v, int len) -{ - int ret; - struct p9_trans_fd *ts = NULL; - - if (client && client->status != Disconnected) - ts = client->trans; - - if (!ts) - return -EREMOTEIO; - - if (!(ts->rd->f_flags & O_NONBLOCK)) - P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n"); - - ret = kernel_read(ts->rd, ts->rd->f_pos, v, len); - if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) - client->status = Disconnected; - return ret; -} - -/** - * p9_fd_write - write to a socket - * @client: client instance - * @v: buffer to send data from - * @len: size of send buffer + * p9_mux_destroy - cancels all pending requests and frees mux resources + * @m: mux to destroy * */ -static int p9_fd_write(struct p9_client *client, void *v, int len) -{ - int ret; - mm_segment_t oldfs; - struct p9_trans_fd *ts = NULL; - - if (client && client->status != Disconnected) - ts = client->trans; - - if (!ts) - return -EREMOTEIO; - - if (!(ts->wr->f_flags & O_NONBLOCK)) - P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n"); - - 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); - set_fs(oldfs); - - if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) - client->status = Disconnected; - return ret; -} - -static unsigned int -p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt) +static void p9_conn_destroy(struct p9_conn *m) { - int ret, n; - struct p9_trans_fd *ts = NULL; - - if (client && client->status == Connected) - ts = client->trans; - - if (!ts) - 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; + P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m, + m->mux_list.prev, m->mux_list.next); - ret = ts->rd->f_op->poll(ts->rd, pt); - if (ret < 0) - return ret; + p9_mux_poll_stop(m); + cancel_work_sync(&m->rq); + cancel_work_sync(&m->wq); - if (ts->rd != ts->wr) { - n = ts->wr->f_op->poll(ts->wr, pt); - if (n < 0) - return n; - ret = (ret & ~POLLOUT) | (n & ~POLLIN); - } + p9_conn_cancel(m, -ECONNRESET); - return ret; + m->client = NULL; + p9_idpool_destroy(m->tagpool); + kfree(m); } /** @@ -1492,6 +1401,49 @@ static struct p9_trans_module p9_fd_trans = { .owner = THIS_MODULE, }; +/** + * p9_poll_proc - poll worker thread + * @a: thread state and arguments + * + * polls all v9fs transports for new events and queues the appropriate + * work to the work queue + * + */ + +static int p9_poll_proc(void *a) +{ + unsigned long flags; + + P9_DPRINTK(P9_DEBUG_MUX, "start %p\n", current); + repeat: + spin_lock_irqsave(&p9_poll_lock, flags); + while (!list_empty(&p9_poll_pending_list)) { + struct p9_conn *conn = list_first_entry(&p9_poll_pending_list, + struct p9_conn, + poll_pending_link); + list_del_init(&conn->poll_pending_link); + spin_unlock_irqrestore(&p9_poll_lock, flags); + + p9_poll_mux(conn); + + spin_lock_irqsave(&p9_poll_lock, flags); + } + spin_unlock_irqrestore(&p9_poll_lock, flags); + + set_current_state(TASK_INTERRUPTIBLE); + if (list_empty(&p9_poll_pending_list)) { + P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n"); + schedule(); + } + __set_current_state(TASK_RUNNING); + + if (!kthread_should_stop()) + goto repeat; + + P9_DPRINTK(P9_DEBUG_MUX, "finish\n"); + return 0; +} + int p9_trans_fd_init(void) { p9_mux_wq = create_workqueue("v9fs"); -- cgit v1.2.3 From 21c003687e2d1c589cf177a3ba17fd439af94850 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:24 -0500 Subject: 9p: consolidate mux_rpc and request structure Currently, trans_fd has two structures (p9_req and p9_mux-rpc) which contain mostly duplicate data. This patch consolidates these two structures and removes p9_mux_rpc. Signed-off-by: Eric Van Hensbergen --- net/9p/trans_fd.c | 68 ++++++++++++++++++------------------------------------- 1 file changed, 22 insertions(+), 46 deletions(-) (limited to 'net/9p/trans_fd.c') diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 334d39cc5ba3..dbb057d7fa5f 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -119,6 +119,8 @@ typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a); * @cba: argument to pass to callback * @flush: flag to indicate RPC has been flushed * @req_list: list link for higher level objects to chain requests + * @m: connection this request was issued on + * @wqueue: wait queue that client is blocked on for this rpc * */ @@ -132,6 +134,8 @@ struct p9_req { void *cba; int flush; struct list_head req_list; + struct p9_conn *m; + wait_queue_head_t wqueue; }; struct p9_poll_wait { @@ -186,25 +190,6 @@ struct p9_conn { unsigned long wsched; }; -/** - * struct p9_mux_rpc - fd mux rpc accounting structure - * @m: connection this request was issued on - * @err: error state - * @tcall: request &p9_fcall - * @rcall: response &p9_fcall - * @wqueue: wait queue that client is blocked on for this rpc - * - * Bug: isn't this information duplicated elsewhere like &p9_req - */ - -struct p9_mux_rpc { - struct p9_conn *m; - int err; - struct p9_fcall *tcall; - struct p9_fcall *rcall; - wait_queue_head_t wqueue; -}; - static DEFINE_SPINLOCK(p9_poll_lock); static LIST_HEAD(p9_poll_pending_list); static struct workqueue_struct *p9_mux_wq; @@ -844,6 +829,8 @@ static struct p9_req *p9_send_request(struct p9_conn *m, #endif spin_lock_init(&req->lock); + req->m = m; + init_waitqueue_head(&req->wqueue); req->tag = n; req->tcall = tc; req->rcall = NULL; @@ -954,20 +941,14 @@ p9_mux_flush_request(struct p9_conn *m, struct p9_req *req) return 1; } -static void -p9_conn_rpc_cb(struct p9_req *req, void *a) +static void p9_conn_rpc_cb(struct p9_req *req, void *a) { - struct p9_mux_rpc *r; - - P9_DPRINTK(P9_DEBUG_MUX, "req %p r %p\n", req, a); - r = a; - r->rcall = req->rcall; - r->err = req->err; + P9_DPRINTK(P9_DEBUG_MUX, "req %p arg %p\n", req, a); if (req->flush != None && !req->err) - r->err = -ERESTARTSYS; + req->err = -ERESTARTSYS; - wake_up(&r->wqueue); + wake_up(&req->wqueue); } /** @@ -987,13 +968,6 @@ p9_fd_rpc(struct p9_client *client, struct p9_fcall *tc, struct p9_fcall **rc) int err, sigpending; unsigned long flags; struct p9_req *req; - struct p9_mux_rpc r; - - r.err = 0; - r.tcall = tc; - r.rcall = NULL; - r.m = m; - init_waitqueue_head(&r.wqueue); if (rc) *rc = NULL; @@ -1004,16 +978,17 @@ p9_fd_rpc(struct p9_client *client, struct p9_fcall *tc, struct p9_fcall **rc) clear_thread_flag(TIF_SIGPENDING); } - req = p9_send_request(m, tc, p9_conn_rpc_cb, &r); + req = p9_send_request(m, tc, p9_conn_rpc_cb, NULL); if (IS_ERR(req)) { err = PTR_ERR(req); P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err); return err; } - err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0); - if (r.err < 0) - err = r.err; + err = wait_event_interruptible(req->wqueue, req->rcall != NULL || + req->err < 0); + if (req->err < 0) + err = req->err; if (err == -ERESTARTSYS && client->status == Connected && m->err == 0) { @@ -1021,10 +996,11 @@ p9_fd_rpc(struct p9_client *client, struct p9_fcall *tc, struct p9_fcall **rc) /* wait until we get response of the flush message */ do { clear_thread_flag(TIF_SIGPENDING); - err = wait_event_interruptible(r.wqueue, - r.rcall || r.err); - } while (!r.rcall && !r.err && err == -ERESTARTSYS && - client->status == Connected && !m->err); + err = wait_event_interruptible(req->wqueue, + req->rcall || req->err); + } while (!req->rcall && !req->err && + err == -ERESTARTSYS && + client->status == Connected && !m->err); err = -ERESTARTSYS; } @@ -1038,9 +1014,9 @@ p9_fd_rpc(struct p9_client *client, struct p9_fcall *tc, struct p9_fcall **rc) } if (rc) - *rc = r.rcall; + *rc = req->rcall; else - kfree(r.rcall); + kfree(req->rcall); p9_mux_free_request(m, req); if (err > 0) -- cgit v1.2.3 From 044c7768841f1ef39f951972d3c1e6537a535030 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:23 -0500 Subject: 9p: eliminate callback complexity The current trans_fd rpc mechanisms use a dynamic callback mechanism which introduces a lot of complexity which only accomodates a single special case. This patch removes much of that complexity in favor of a simple exception mechanism to deal with flushes. Signed-off-by: Eric Van Hensbergen --- net/9p/trans_fd.c | 149 ++++++++++++++++++++++++------------------------------ 1 file changed, 66 insertions(+), 83 deletions(-) (limited to 'net/9p/trans_fd.c') diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index dbb057d7fa5f..180163b3e8f9 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -105,9 +105,6 @@ enum { Flushed, }; -struct p9_req; -typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a); - /** * struct p9_req - fd mux encoding of an rpc transaction * @lock: protects req_list @@ -115,8 +112,6 @@ typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a); * @tcall: request &p9_fcall structure * @rcall: response &p9_fcall structure * @err: error state - * @cb: callback for when response is received - * @cba: argument to pass to callback * @flush: flag to indicate RPC has been flushed * @req_list: list link for higher level objects to chain requests * @m: connection this request was issued on @@ -130,8 +125,6 @@ struct p9_req { struct p9_fcall *tcall; struct p9_fcall *rcall; int err; - p9_conn_req_callback cb; - void *cba; int flush; struct list_head req_list; struct p9_conn *m; @@ -231,6 +224,65 @@ static void p9_mux_poll_stop(struct p9_conn *m) spin_unlock_irqrestore(&p9_poll_lock, flags); } +static void p9_mux_free_request(struct p9_conn *m, struct p9_req *req) +{ + p9_mux_put_tag(m, req->tag); + kfree(req); +} + +static void p9_conn_rpc_cb(struct p9_req *req); + +static void p9_mux_flush_cb(struct p9_req *freq) +{ + int tag; + struct p9_conn *m = freq->m; + struct p9_req *req, *rreq, *rptr; + + P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m, + freq->tcall, freq->rcall, freq->err, + freq->tcall->params.tflush.oldtag); + + spin_lock(&m->lock); + tag = freq->tcall->params.tflush.oldtag; + req = NULL; + list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { + if (rreq->tag == tag) { + req = rreq; + list_del(&req->req_list); + break; + } + } + spin_unlock(&m->lock); + + if (req) { + spin_lock(&req->lock); + req->flush = Flushed; + spin_unlock(&req->lock); + + p9_conn_rpc_cb(req); + } + + kfree(freq->tcall); + kfree(freq->rcall); + p9_mux_free_request(m, freq); +} + +static void p9_conn_rpc_cb(struct p9_req *req) +{ + P9_DPRINTK(P9_DEBUG_MUX, "req %p\n", req); + + if (req->tcall->id == P9_TFLUSH) { /* flush callback */ + P9_DPRINTK(P9_DEBUG_MUX, "flush req %p\n", req); + p9_mux_flush_cb(req); + } else { /* normal wakeup path */ + P9_DPRINTK(P9_DEBUG_MUX, "normal req %p\n", req); + if (req->flush != None && !req->err) + req->err = -ERESTARTSYS; + + wake_up(&req->wqueue); + } +} + /** * p9_conn_cancel - cancel all pending requests with error * @m: mux data @@ -259,10 +311,7 @@ void p9_conn_cancel(struct p9_conn *m, int err) if (!req->err) req->err = err; - if (req->cb) - (*req->cb) (req, req->cba); - else - kfree(req->rcall); + p9_conn_rpc_cb(req); } } @@ -472,12 +521,8 @@ static void p9_read_work(struct work_struct *work) req->rcall = rcall; process_request(m, req); - if (req->flush != Flushing) { - if (req->cb) - (*req->cb) (req, req->cba); - else - kfree(req->rcall); - } + if (req->flush != Flushing) + p9_conn_rpc_cb(req); } else { if (err >= 0 && rcall->id != P9_RFLUSH) P9_DPRINTK(P9_DEBUG_ERROR, @@ -786,14 +831,10 @@ static void p9_poll_mux(struct p9_conn *m) * * @m: mux data * @tc: request to be sent - * @cb: callback function to call when response is received - * @cba: parameter to pass to the callback function * */ -static struct p9_req *p9_send_request(struct p9_conn *m, - struct p9_fcall *tc, - p9_conn_req_callback cb, void *cba) +static struct p9_req *p9_send_request(struct p9_conn *m, struct p9_fcall *tc) { int n; struct p9_req *req; @@ -835,8 +876,6 @@ static struct p9_req *p9_send_request(struct p9_conn *m, req->tcall = tc; req->rcall = NULL; req->err = 0; - req->cb = cb; - req->cba = cba; req->flush = None; spin_lock(&m->lock); @@ -854,51 +893,6 @@ static struct p9_req *p9_send_request(struct p9_conn *m, return req; } -static void p9_mux_free_request(struct p9_conn *m, struct p9_req *req) -{ - p9_mux_put_tag(m, req->tag); - kfree(req); -} - -static void p9_mux_flush_cb(struct p9_req *freq, void *a) -{ - int tag; - struct p9_conn *m; - struct p9_req *req, *rreq, *rptr; - - m = a; - P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m, - freq->tcall, freq->rcall, freq->err, - freq->tcall->params.tflush.oldtag); - - spin_lock(&m->lock); - tag = freq->tcall->params.tflush.oldtag; - req = NULL; - list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { - if (rreq->tag == tag) { - req = rreq; - list_del(&req->req_list); - break; - } - } - spin_unlock(&m->lock); - - if (req) { - spin_lock(&req->lock); - req->flush = Flushed; - spin_unlock(&req->lock); - - if (req->cb) - (*req->cb) (req, req->cba); - else - kfree(req->rcall); - } - - kfree(freq->tcall); - kfree(freq->rcall); - p9_mux_free_request(m, freq); -} - static int p9_mux_flush_request(struct p9_conn *m, struct p9_req *req) { @@ -928,8 +922,7 @@ p9_mux_flush_request(struct p9_conn *m, struct p9_req *req) list_del(&rreq->req_list); req->flush = Flushed; spin_unlock(&m->lock); - if (req->cb) - (*req->cb) (req, req->cba); + p9_conn_rpc_cb(req); return 0; } } @@ -937,20 +930,10 @@ p9_mux_flush_request(struct p9_conn *m, struct p9_req *req) clear_thread_flag(TIF_SIGPENDING); fc = p9_create_tflush(req->tag); - p9_send_request(m, fc, p9_mux_flush_cb, m); + p9_send_request(m, fc); return 1; } -static void p9_conn_rpc_cb(struct p9_req *req, void *a) -{ - P9_DPRINTK(P9_DEBUG_MUX, "req %p arg %p\n", req, a); - - if (req->flush != None && !req->err) - req->err = -ERESTARTSYS; - - wake_up(&req->wqueue); -} - /** * p9_fd_rpc- sends 9P request and waits until a response is available. * The function can be interrupted. @@ -978,7 +961,7 @@ p9_fd_rpc(struct p9_client *client, struct p9_fcall *tc, struct p9_fcall **rc) clear_thread_flag(TIF_SIGPENDING); } - req = p9_send_request(m, tc, p9_conn_rpc_cb, NULL); + req = p9_send_request(m, tc); if (IS_ERR(req)) { err = PTR_ERR(req); P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err); -- cgit v1.2.3 From ff683452f7bc52d7fd653cf5e67b1134555734c7 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:22 -0500 Subject: 9p: apply common tagpool handling to trans_fd Simplify trans_fd by using new common client tagpool structure. Signed-off-by: Eric Van Hensbergen --- net/9p/trans_fd.c | 44 ++++++++++---------------------------------- 1 file changed, 10 insertions(+), 34 deletions(-) (limited to 'net/9p/trans_fd.c') diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 180163b3e8f9..6243093934b2 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -142,7 +142,6 @@ struct p9_poll_wait { * @lock: protects mux_list (?) * @mux_list: list link for mux to manage multiple connections (?) * @client: reference to client instance for this connection - * @tagpool: id accounting for transactions * @err: error state * @req_list: accounting for requests which have been sent * @unsent_req_list: accounting for requests that haven't been sent @@ -165,7 +164,6 @@ struct p9_conn { spinlock_t lock; /* protect lock structure */ struct list_head mux_list; struct p9_client *client; - struct p9_idpool *tagpool; int err; struct list_head req_list; struct list_head unsent_req_list; @@ -188,23 +186,6 @@ static LIST_HEAD(p9_poll_pending_list); static struct workqueue_struct *p9_mux_wq; static struct task_struct *p9_poll_task; -static u16 p9_mux_get_tag(struct p9_conn *m) -{ - int tag; - - tag = p9_idpool_get(m->tagpool); - if (tag < 0) - return P9_NOTAG; - else - return (u16) tag; -} - -static void p9_mux_put_tag(struct p9_conn *m, u16 tag) -{ - if (tag != P9_NOTAG && p9_idpool_check(tag, m->tagpool)) - p9_idpool_put(tag, m->tagpool); -} - static void p9_mux_poll_stop(struct p9_conn *m) { unsigned long flags; @@ -226,7 +207,9 @@ static void p9_mux_poll_stop(struct p9_conn *m) static void p9_mux_free_request(struct p9_conn *m, struct p9_req *req) { - p9_mux_put_tag(m, req->tag); + if (req->tag != P9_NOTAG && + p9_idpool_check(req->tag, m->client->tagpool)) + p9_idpool_put(req->tag, m->client->tagpool); kfree(req); } @@ -745,11 +728,6 @@ static struct p9_conn *p9_conn_create(struct p9_client *client) spin_lock_init(&m->lock); INIT_LIST_HEAD(&m->mux_list); m->client = client; - m->tagpool = p9_idpool_create(); - if (IS_ERR(m->tagpool)) { - kfree(m); - return ERR_PTR(-ENOMEM); - } INIT_LIST_HEAD(&m->req_list); INIT_LIST_HEAD(&m->unsent_req_list); @@ -848,14 +826,13 @@ static struct p9_req *p9_send_request(struct p9_conn *m, struct p9_fcall *tc) if (!req) return ERR_PTR(-ENOMEM); - if (tc->id == P9_TVERSION) - n = P9_NOTAG; - else - n = p9_mux_get_tag(m); - - if (n < 0) { - kfree(req); - return ERR_PTR(-ENOMEM); + n = P9_NOTAG; + if (tc->id != P9_TVERSION) { + n = p9_idpool_get(m->client->tagpool); + if (n < 0) { + kfree(req); + return ERR_PTR(-ENOMEM); + } } p9_set_tag(tc, n); @@ -1134,7 +1111,6 @@ static void p9_conn_destroy(struct p9_conn *m) p9_conn_cancel(m, -ECONNRESET); m->client = NULL; - p9_idpool_destroy(m->tagpool); kfree(m); } -- cgit v1.2.3 From 673d62cdaac6ffbce980a349d3174b3929ceb9e5 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:22 -0500 Subject: 9p: apply common request code to trans_fd Apply the now common p9_req_t structure to the fd transport. Signed-off-by: Eric Van Hensbergen --- include/net/9p/client.h | 10 +- net/9p/client.c | 21 ++++ net/9p/trans_fd.c | 262 ++++++++++++++++++------------------------------ net/9p/trans_virtio.c | 5 +- 4 files changed, 126 insertions(+), 172 deletions(-) (limited to 'net/9p/trans_fd.c') diff --git a/include/net/9p/client.h b/include/net/9p/client.h index 140cf1d58452..4fecaabd17bd 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -49,11 +49,12 @@ enum p9_trans_status { * enum p9_req_status_t - virtio request status * @REQ_STATUS_IDLE: request slot unused * @REQ_STATUS_ALLOC: request has been allocated but not sent + * @REQ_STATUS_UNSENT: request waiting to be sent * @REQ_STATUS_SENT: request sent to server * @REQ_STATUS_FLSH: a flush has been sent for this request * @REQ_STATUS_RCVD: response received from server * @REQ_STATUS_FLSHD: request has been flushed - * @REQ_STATUS_ERR: request encountered an error on the client side + * @REQ_STATUS_ERROR: request encountered an error on the client side * * The @REQ_STATUS_IDLE state is used to mark a request slot as unused * but use is actually tracked by the idpool structure which handles tag @@ -64,6 +65,7 @@ enum p9_trans_status { enum p9_req_status_t { REQ_STATUS_IDLE, REQ_STATUS_ALLOC, + REQ_STATUS_UNSENT, REQ_STATUS_SENT, REQ_STATUS_FLSH, REQ_STATUS_RCVD, @@ -79,6 +81,8 @@ enum p9_req_status_t { * @tc: the request fcall structure * @rc: the response fcall structure * @aux: transport specific data (provided for trans_fd migration) + * @tag: tag on request (BUG: redundant) + * @req_list: link for higher level objects to chain requests * * Transport use an array to track outstanding requests * instead of a list. While this may incurr overhead during initial @@ -99,6 +103,9 @@ struct p9_req_t { struct p9_fcall *rc; u16 flush_tag; void *aux; + + int tag; + struct list_head req_list; }; /** @@ -207,5 +214,6 @@ struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset); struct p9_req_t *p9_tag_alloc(struct p9_client *, u16); struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); +void p9_free_req(struct p9_client *, struct p9_req_t *); #endif /* NET_9P_CLIENT_H */ diff --git a/net/9p/client.c b/net/9p/client.c index 867031934f75..f2d07ef9e6a4 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -268,6 +268,27 @@ static void p9_tag_cleanup(struct p9_client *c) c->max_tag = 0; } +/** + * p9_free_req - free a request and clean-up as necessary + * c: client state + * r: request to release + * + */ + +void p9_free_req(struct p9_client *c, struct p9_req_t *r) +{ + r->flush_tag = P9_NOTAG; + r->status = REQ_STATUS_IDLE; + if (r->tc->tag != P9_NOTAG && p9_idpool_check(r->tc->tag, c->tagpool)) + p9_idpool_put(r->tc->tag, c->tagpool); + + /* if this was a flush request we have to free response fcall */ + if (r->tc->id == P9_TFLUSH) { + kfree(r->tc); + kfree(r->rc); + } +} + static struct p9_fid *p9_fid_create(struct p9_client *clnt) { int err; diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 6243093934b2..cc9bc739e9d3 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -44,7 +44,6 @@ #define P9_PORT 564 #define MAX_SOCK_BUF (64*1024) -#define ERREQFLUSH 1 #define MAXPOLLWADDR 2 /** @@ -99,38 +98,6 @@ enum { Wpending = 8, /* can write */ }; -enum { - None, - Flushing, - Flushed, -}; - -/** - * struct p9_req - fd mux encoding of an rpc transaction - * @lock: protects req_list - * @tag: numeric tag for rpc transaction - * @tcall: request &p9_fcall structure - * @rcall: response &p9_fcall structure - * @err: error state - * @flush: flag to indicate RPC has been flushed - * @req_list: list link for higher level objects to chain requests - * @m: connection this request was issued on - * @wqueue: wait queue that client is blocked on for this rpc - * - */ - -struct p9_req { - spinlock_t lock; - int tag; - struct p9_fcall *tcall; - struct p9_fcall *rcall; - int err; - int flush; - struct list_head req_list; - struct p9_conn *m; - wait_queue_head_t wqueue; -}; - struct p9_poll_wait { struct p9_conn *conn; wait_queue_t wait; @@ -139,7 +106,6 @@ struct p9_poll_wait { /** * struct p9_conn - fd mux connection state information - * @lock: protects mux_list (?) * @mux_list: list link for mux to manage multiple connections (?) * @client: reference to client instance for this connection * @err: error state @@ -161,7 +127,6 @@ struct p9_poll_wait { */ struct p9_conn { - spinlock_t lock; /* protect lock structure */ struct list_head mux_list; struct p9_client *client; int err; @@ -205,64 +170,41 @@ static void p9_mux_poll_stop(struct p9_conn *m) spin_unlock_irqrestore(&p9_poll_lock, flags); } -static void p9_mux_free_request(struct p9_conn *m, struct p9_req *req) -{ - if (req->tag != P9_NOTAG && - p9_idpool_check(req->tag, m->client->tagpool)) - p9_idpool_put(req->tag, m->client->tagpool); - kfree(req); -} - -static void p9_conn_rpc_cb(struct p9_req *req); +static void p9_conn_rpc_cb(struct p9_client *, struct p9_req_t *); -static void p9_mux_flush_cb(struct p9_req *freq) +static void p9_mux_flush_cb(struct p9_client *client, struct p9_req_t *freq) { - int tag; - struct p9_conn *m = freq->m; - struct p9_req *req, *rreq, *rptr; + struct p9_conn *m = client->trans; + struct p9_req_t *req; P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m, - freq->tcall, freq->rcall, freq->err, - freq->tcall->params.tflush.oldtag); - - spin_lock(&m->lock); - tag = freq->tcall->params.tflush.oldtag; - req = NULL; - list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { - if (rreq->tag == tag) { - req = rreq; - list_del(&req->req_list); - break; - } - } - spin_unlock(&m->lock); + freq->tc, freq->rc, freq->t_err, + freq->tc->params.tflush.oldtag); + req = p9_tag_lookup(client, freq->tc->params.tflush.oldtag); if (req) { - spin_lock(&req->lock); - req->flush = Flushed; - spin_unlock(&req->lock); - - p9_conn_rpc_cb(req); + req->status = REQ_STATUS_FLSHD; + list_del(&req->req_list); + p9_conn_rpc_cb(client, req); } - kfree(freq->tcall); - kfree(freq->rcall); - p9_mux_free_request(m, freq); + p9_free_req(client, freq); } -static void p9_conn_rpc_cb(struct p9_req *req) +static void p9_conn_rpc_cb(struct p9_client *client, struct p9_req_t *req) { P9_DPRINTK(P9_DEBUG_MUX, "req %p\n", req); - if (req->tcall->id == P9_TFLUSH) { /* flush callback */ + if (req->tc->id == P9_TFLUSH) { /* flush callback */ P9_DPRINTK(P9_DEBUG_MUX, "flush req %p\n", req); - p9_mux_flush_cb(req); + p9_mux_flush_cb(client, req); } else { /* normal wakeup path */ P9_DPRINTK(P9_DEBUG_MUX, "normal req %p\n", req); - if (req->flush != None && !req->err) - req->err = -ERESTARTSYS; + if (!req->t_err && (req->status == REQ_STATUS_FLSHD || + req->status == REQ_STATUS_FLSH)) + req->t_err = -ERESTARTSYS; - wake_up(&req->wqueue); + wake_up(req->wq); } } @@ -275,59 +217,62 @@ static void p9_conn_rpc_cb(struct p9_req *req) void p9_conn_cancel(struct p9_conn *m, int err) { - struct p9_req *req, *rtmp; + struct p9_req_t *req, *rtmp; LIST_HEAD(cancel_list); P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err); m->err = err; - spin_lock(&m->lock); + spin_lock(&m->client->lock); list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { + req->status = REQ_STATUS_ERROR; + if (!req->t_err) + req->t_err = err; list_move(&req->req_list, &cancel_list); } list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { + req->status = REQ_STATUS_ERROR; + if (!req->t_err) + req->t_err = err; list_move(&req->req_list, &cancel_list); } - spin_unlock(&m->lock); + spin_unlock(&m->client->lock); list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { list_del(&req->req_list); - if (!req->err) - req->err = err; - - p9_conn_rpc_cb(req); + p9_conn_rpc_cb(m->client, req); } } -static void process_request(struct p9_conn *m, struct p9_req *req) +static void process_request(struct p9_conn *m, struct p9_req_t *req) { int ecode; struct p9_str *ename; - if (!req->err && req->rcall->id == P9_RERROR) { - ecode = req->rcall->params.rerror.errno; - ename = &req->rcall->params.rerror.error; + if (!req->t_err && req->rc->id == P9_RERROR) { + ecode = req->rc->params.rerror.errno; + ename = &req->rc->params.rerror.error; P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len, ename->str); if (m->client->dotu) - req->err = -ecode; + req->t_err = -ecode; - if (!req->err) { - req->err = p9_errstr2errno(ename->str, ename->len); + if (!req->t_err) { + req->t_err = p9_errstr2errno(ename->str, ename->len); /* string match failed */ - if (!req->err) { - PRINT_FCALL_ERROR("unknown error", req->rcall); - req->err = -ESERVERFAULT; + if (!req->t_err) { + PRINT_FCALL_ERROR("unknown error", req->rc); + req->t_err = -ESERVERFAULT; } } - } else if (req->tcall && req->rcall->id != req->tcall->id + 1) { + } else if (req->tc && req->rc->id != req->tc->id + 1) { P9_DPRINTK(P9_DEBUG_ERROR, "fcall mismatch: expected %d, got %d\n", - req->tcall->id + 1, req->rcall->id); - if (!req->err) - req->err = -EIO; + req->tc->id + 1, req->rc->id); + if (!req->t_err) + req->t_err = -EIO; } } @@ -401,7 +346,7 @@ static void p9_read_work(struct work_struct *work) { int n, err; struct p9_conn *m; - struct p9_req *req, *rptr, *rreq; + struct p9_req_t *req; struct p9_fcall *rcall; char *rbuf; @@ -488,24 +433,19 @@ static void p9_read_work(struct work_struct *work) P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, rcall->id, rcall->tag); - req = NULL; - spin_lock(&m->lock); - list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { - if (rreq->tag == rcall->tag) { - req = rreq; - if (req->flush != Flushing) - list_del(&req->req_list); - break; - } - } - spin_unlock(&m->lock); + req = p9_tag_lookup(m->client, rcall->tag); if (req) { - req->rcall = rcall; + if (req->status != REQ_STATUS_FLSH) { + list_del(&req->req_list); + req->status = REQ_STATUS_RCVD; + } + + req->rc = rcall; process_request(m, req); - if (req->flush != Flushing) - p9_conn_rpc_cb(req); + if (req->status != REQ_STATUS_FLSH) + p9_conn_rpc_cb(m->client, req); } else { if (err >= 0 && rcall->id != P9_RFLUSH) P9_DPRINTK(P9_DEBUG_ERROR, @@ -580,7 +520,7 @@ static void p9_write_work(struct work_struct *work) { int n, err; struct p9_conn *m; - struct p9_req *req; + struct p9_req_t *req; m = container_of(work, struct p9_conn, wq); @@ -595,18 +535,16 @@ static void p9_write_work(struct work_struct *work) return; } - spin_lock(&m->lock); -again: - req = list_entry(m->unsent_req_list.next, struct p9_req, + spin_lock(&m->client->lock); + req = list_entry(m->unsent_req_list.next, struct p9_req_t, req_list); + req->status = REQ_STATUS_SENT; list_move_tail(&req->req_list, &m->req_list); - if (req->err == ERREQFLUSH) - goto again; - m->wbuf = req->tcall->sdata; - m->wsize = req->tcall->size; + m->wbuf = req->tc->sdata; + m->wsize = req->tc->size; m->wpos = 0; - spin_unlock(&m->lock); + spin_unlock(&m->client->lock); } P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos, @@ -725,7 +663,6 @@ static struct p9_conn *p9_conn_create(struct p9_client *client) if (!m) return ERR_PTR(-ENOMEM); - spin_lock_init(&m->lock); INIT_LIST_HEAD(&m->mux_list); m->client = client; @@ -812,30 +749,27 @@ static void p9_poll_mux(struct p9_conn *m) * */ -static struct p9_req *p9_send_request(struct p9_conn *m, struct p9_fcall *tc) +static struct p9_req_t *p9_send_request(struct p9_conn *m, struct p9_fcall *tc) { + int tag; int n; - struct p9_req *req; + struct p9_req_t *req; P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current, tc, tc->id); if (m->err < 0) return ERR_PTR(m->err); - req = kmalloc(sizeof(struct p9_req), GFP_KERNEL); - if (!req) - return ERR_PTR(-ENOMEM); - - n = P9_NOTAG; + tag = P9_NOTAG; if (tc->id != P9_TVERSION) { - n = p9_idpool_get(m->client->tagpool); - if (n < 0) { - kfree(req); + tag = p9_idpool_get(m->client->tagpool); + if (tag < 0) return ERR_PTR(-ENOMEM); - } } - p9_set_tag(tc, n); + p9_set_tag(tc, tag); + + req = p9_tag_alloc(m->client, tag); #ifdef CONFIG_NET_9P_DEBUG if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { @@ -846,18 +780,15 @@ static struct p9_req *p9_send_request(struct p9_conn *m, struct p9_fcall *tc) } #endif - spin_lock_init(&req->lock); - req->m = m; - init_waitqueue_head(&req->wqueue); - req->tag = n; - req->tcall = tc; - req->rcall = NULL; - req->err = 0; - req->flush = None; + req->tag = tag; + req->tc = tc; + req->rc = NULL; + req->t_err = 0; + req->status = REQ_STATUS_UNSENT; - spin_lock(&m->lock); + spin_lock(&m->client->lock); list_add_tail(&req->req_list, &m->unsent_req_list); - spin_unlock(&m->lock); + spin_unlock(&m->client->lock); if (test_and_clear_bit(Wpending, &m->wsched)) n = POLLOUT; @@ -871,39 +802,36 @@ static struct p9_req *p9_send_request(struct p9_conn *m, struct p9_fcall *tc) } static int -p9_mux_flush_request(struct p9_conn *m, struct p9_req *req) +p9_mux_flush_request(struct p9_conn *m, struct p9_req_t *req) { struct p9_fcall *fc; - struct p9_req *rreq, *rptr; + struct p9_req_t *rreq, *rptr; P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag); /* if a response was received for a request, do nothing */ - spin_lock(&req->lock); - if (req->rcall || req->err) { - spin_unlock(&req->lock); + if (req->rc || req->t_err) { P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p response already received\n", m, req); return 0; } - req->flush = Flushing; - spin_unlock(&req->lock); + req->status = REQ_STATUS_FLSH; - spin_lock(&m->lock); + spin_lock(&m->client->lock); /* if the request is not sent yet, just remove it from the list */ list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) { if (rreq->tag == req->tag) { P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p request is not sent yet\n", m, req); list_del(&rreq->req_list); - req->flush = Flushed; - spin_unlock(&m->lock); - p9_conn_rpc_cb(req); + req->status = REQ_STATUS_FLSHD; + spin_unlock(&m->client->lock); + p9_conn_rpc_cb(m->client, req); return 0; } } - spin_unlock(&m->lock); + spin_unlock(&m->client->lock); clear_thread_flag(TIF_SIGPENDING); fc = p9_create_tflush(req->tag); @@ -927,7 +855,7 @@ p9_fd_rpc(struct p9_client *client, struct p9_fcall *tc, struct p9_fcall **rc) struct p9_conn *m = p->conn; int err, sigpending; unsigned long flags; - struct p9_req *req; + struct p9_req_t *req; if (rc) *rc = NULL; @@ -945,10 +873,10 @@ p9_fd_rpc(struct p9_client *client, struct p9_fcall *tc, struct p9_fcall **rc) return err; } - err = wait_event_interruptible(req->wqueue, req->rcall != NULL || - req->err < 0); - if (req->err < 0) - err = req->err; + err = wait_event_interruptible(*req->wq, req->rc != NULL || + req->t_err < 0); + if (req->t_err < 0) + err = req->t_err; if (err == -ERESTARTSYS && client->status == Connected && m->err == 0) { @@ -956,9 +884,9 @@ p9_fd_rpc(struct p9_client *client, struct p9_fcall *tc, struct p9_fcall **rc) /* wait until we get response of the flush message */ do { clear_thread_flag(TIF_SIGPENDING); - err = wait_event_interruptible(req->wqueue, - req->rcall || req->err); - } while (!req->rcall && !req->err && + err = wait_event_interruptible(*req->wq, + req->rc || req->t_err); + } while (!req->rc && !req->t_err && err == -ERESTARTSYS && client->status == Connected && !m->err); @@ -974,11 +902,11 @@ p9_fd_rpc(struct p9_client *client, struct p9_fcall *tc, struct p9_fcall **rc) } if (rc) - *rc = req->rcall; + *rc = req->rc; else - kfree(req->rcall); + kfree(req->rc); - p9_mux_free_request(m, req); + p9_free_req(client, req); if (err > 0) err = -EIO; diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 36bce45e4e44..e18de14c30d5 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -247,10 +247,7 @@ p9_virtio_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) } #endif - if (n != P9_NOTAG && p9_idpool_check(n, c->tagpool)) - p9_idpool_put(n, c->tagpool); - - req->status = REQ_STATUS_IDLE; + p9_free_req(c, req); return 0; } -- cgit v1.2.3 From 1b0a763bdd5ed467d0e03b88e045000c749303fb Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:22 -0500 Subject: 9p: use the rcall structure passed in the request in trans_fd read_work This patch reworks the read_work function to enable it to directly use a passed in rcall structure. This should help allow us to remove unnecessary copies in the future. Signed-off-by: Eric Van Hensbergen --- net/9p/trans_fd.c | 129 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 66 insertions(+), 63 deletions(-) (limited to 'net/9p/trans_fd.c') diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index cc9bc739e9d3..627e3f097fc5 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -111,7 +111,9 @@ struct p9_poll_wait { * @err: error state * @req_list: accounting for requests which have been sent * @unsent_req_list: accounting for requests that haven't been sent - * @rcall: current response &p9_fcall structure + * @req: current request being processed (if any) + * @tmp_buf: temporary buffer to read in header + * @rsize: amount to read for current frame * @rpos: read position in current frame * @rbuf: current read buffer * @wpos: write position for current frame @@ -132,7 +134,9 @@ struct p9_conn { int err; struct list_head req_list; struct list_head unsent_req_list; - struct p9_fcall *rcall; + struct p9_req_t *req; + char tmp_buf[7]; + int rsize; int rpos; char *rbuf; int wpos; @@ -346,34 +350,25 @@ static void p9_read_work(struct work_struct *work) { int n, err; struct p9_conn *m; - struct p9_req_t *req; - struct p9_fcall *rcall; - char *rbuf; m = container_of(work, struct p9_conn, rq); if (m->err < 0) return; - rcall = NULL; P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); - if (!m->rcall) { - m->rcall = - kmalloc(sizeof(struct p9_fcall) + m->client->msize, - GFP_KERNEL); - if (!m->rcall) { - err = -ENOMEM; - goto error; - } - - m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall); + if (!m->rbuf) { + m->rbuf = m->tmp_buf; m->rpos = 0; + m->rsize = 7; /* start by reading header */ } clear_bit(Rpending, &m->wsched); + P9_DPRINTK(P9_DEBUG_MUX, "read mux %p pos %d size: %d = %d\n", m, + m->rpos, m->rsize, m->rsize-m->rpos); err = p9_fd_read(m->client, m->rbuf + m->rpos, - m->client->msize - m->rpos); + m->rsize - m->rpos); P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err); if (err == -EAGAIN) { clear_bit(Rworksched, &m->wsched); @@ -384,8 +379,12 @@ static void p9_read_work(struct work_struct *work) goto error; m->rpos += err; - while (m->rpos > 4) { - n = le32_to_cpu(*(__le32 *) m->rbuf); + + if ((!m->req) && (m->rpos == m->rsize)) { /* header read in */ + u16 tag; + P9_DPRINTK(P9_DEBUG_MUX, "got new header\n"); + + n = le32_to_cpu(*(__le32 *) m->rbuf); /* read packet size */ if (n >= m->client->msize) { P9_DPRINTK(P9_DEBUG_ERROR, "requested packet size too big: %d\n", n); @@ -393,66 +392,71 @@ static void p9_read_work(struct work_struct *work) goto error; } - if (m->rpos < n) - break; + tag = le16_to_cpu(*(__le16 *) (m->rbuf+5)); /* read tag */ + P9_DPRINTK(P9_DEBUG_MUX, "mux %p pkt: size: %d bytes tag: %d\n", + m, n, tag); - err = - p9_deserialize_fcall(m->rbuf, n, m->rcall, m->client->dotu); - if (err < 0) + m->req = p9_tag_lookup(m->client, tag); + if (!m->req) { + P9_DPRINTK(P9_DEBUG_ERROR, "Unexpected packet tag %d\n", + tag); + err = -EIO; goto error; + } + + if (m->req->rc == NULL) { + m->req->rc = kmalloc(sizeof(struct p9_fcall) + + m->client->msize, GFP_KERNEL); + if (!m->req->rc) { + m->req = NULL; + err = -ENOMEM; + goto error; + } + } + m->rbuf = (char *)m->req->rc + sizeof(struct p9_fcall); + memcpy(m->rbuf, m->tmp_buf, m->rsize); + m->rsize = n; + } + + /* not an else because some packets (like clunk) have no payload */ + if ((m->req) && (m->rpos == m->rsize)) { /* packet is read in */ + P9_DPRINTK(P9_DEBUG_MUX, "got new packet\n"); + m->rbuf = (char *)m->req->rc + sizeof(struct p9_fcall); + err = p9_deserialize_fcall(m->rbuf, m->rsize, m->req->rc, + m->client->dotu); + if (err < 0) { + m->req = NULL; + goto error; + } #ifdef CONFIG_NET_9P_DEBUG if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { char buf[150]; - p9_printfcall(buf, sizeof(buf), m->rcall, + p9_printfcall(buf, sizeof(buf), m->req->rc, m->client->dotu); printk(KERN_NOTICE ">>> %p %s\n", m, buf); } #endif - rcall = m->rcall; - rbuf = m->rbuf; - if (m->rpos > n) { - m->rcall = kmalloc(sizeof(struct p9_fcall) + - m->client->msize, GFP_KERNEL); - if (!m->rcall) { - err = -ENOMEM; - goto error; - } + P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, + m->req->rc->id, m->req->rc->tag); - m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall); - memmove(m->rbuf, rbuf + n, m->rpos - n); - m->rpos -= n; - } else { - m->rcall = NULL; - m->rbuf = NULL; - m->rpos = 0; - } + m->rbuf = NULL; + m->rpos = 0; + m->rsize = 0; - P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, - rcall->id, rcall->tag); + if (m->req->status != REQ_STATUS_FLSH) { + list_del(&m->req->req_list); + m->req->status = REQ_STATUS_RCVD; + } - req = p9_tag_lookup(m->client, rcall->tag); + process_request(m, m->req); - if (req) { - if (req->status != REQ_STATUS_FLSH) { - list_del(&req->req_list); - req->status = REQ_STATUS_RCVD; - } + if (m->req->status != REQ_STATUS_FLSH) + p9_conn_rpc_cb(m->client, m->req); - req->rc = rcall; - process_request(m, req); - - if (req->status != REQ_STATUS_FLSH) - p9_conn_rpc_cb(m->client, req); - } else { - if (err >= 0 && rcall->id != P9_RFLUSH) - P9_DPRINTK(P9_DEBUG_ERROR, - "unexpected response mux %p id %d tag %d\n", - m, rcall->id, rcall->tag); - kfree(rcall); - } + m->req = NULL; } if (!list_empty(&m->req_list)) { @@ -470,7 +474,6 @@ static void p9_read_work(struct work_struct *work) clear_bit(Rworksched, &m->wsched); return; - error: p9_conn_cancel(m, err); clear_bit(Rworksched, &m->wsched); -- cgit v1.2.3 From 91b8534fa8f5e01f249b1bf8df0a2540053549ad Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:21 -0500 Subject: 9p: make rpc code common and rework flush code This code moves the rpc function to the common client base, reorganizes the flush code to be more simple and stable, and makes the necessary adjustments to the underlying transports to adapt to the new structure. This reduces the overall amount of code duplication between the transports and should make adding new transports more straightforward. Signed-off-by: Eric Van Hensbergen --- include/net/9p/client.h | 3 +- include/net/9p/transport.h | 8 +- net/9p/client.c | 265 +++++++++++++++++++++++++++++++++++++++++--- net/9p/trans_fd.c | 268 ++++++--------------------------------------- net/9p/trans_virtio.c | 85 ++++---------- 5 files changed, 316 insertions(+), 313 deletions(-) (limited to 'net/9p/trans_fd.c') diff --git a/include/net/9p/client.h b/include/net/9p/client.h index 4fecaabd17bd..6a71d9067818 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -212,8 +212,7 @@ struct p9_stat *p9_client_stat(struct p9_fid *fid); int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst); struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset); -struct p9_req_t *p9_tag_alloc(struct p9_client *, u16); struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); -void p9_free_req(struct p9_client *, struct p9_req_t *); +void p9_client_cb(struct p9_client *c, struct p9_req_t *req); #endif /* NET_9P_CLIENT_H */ diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h index 3e0f2f6beba2..6d5886efb102 100644 --- a/include/net/9p/transport.h +++ b/include/net/9p/transport.h @@ -33,8 +33,8 @@ * @maxsize: transport provided maximum packet size * @def: set if this transport should be considered the default * @create: member function to create a new connection on this transport - * @close: member function to disconnect and close the transport - * @rpc: member function to issue a request to the transport + * @request: member function to issue a request to the transport + * @cancel: member function to cancel a request (if it hasn't been sent) * * This is the basic API for a transport module which is registered by the * transport module with the 9P core network module and used by the client @@ -51,8 +51,8 @@ struct p9_trans_module { struct module *owner; int (*create)(struct p9_client *, const char *, char *); void (*close) (struct p9_client *); - int (*rpc) (struct p9_client *t, struct p9_fcall *tc, - struct p9_fcall **rc); + int (*request) (struct p9_client *, struct p9_req_t *req); + int (*cancel) (struct p9_client *, struct p9_req_t *req); }; void v9fs_register_trans(struct p9_trans_module *m); diff --git a/net/9p/client.c b/net/9p/client.c index f2d07ef9e6a4..29934febecdb 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -55,6 +55,9 @@ static const match_table_t tokens = { {Opt_err, NULL}, }; +static int +p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc); + /** * v9fs_parse_options - parse mount options into session structure * @options: options string passed from mount @@ -268,6 +271,36 @@ static void p9_tag_cleanup(struct p9_client *c) c->max_tag = 0; } +/** + * p9_client_flush - flush (cancel) a request + * c: client state + * req: request to cancel + * + * This sents a flush for a particular requests and links + * the flush request to the original request. The current + * code only supports a single flush request although the protocol + * allows for multiple flush requests to be sent for a single request. + * + */ + +static int p9_client_flush(struct p9_client *c, struct p9_req_t *req) +{ + struct p9_fcall *tc, *rc = NULL; + int err; + + P9_DPRINTK(P9_DEBUG_9P, "client %p tag %d\n", c, req->tc->tag); + + tc = p9_create_tflush(req->tc->tag); + if (IS_ERR(tc)) + return PTR_ERR(tc); + + err = p9_client_rpc(c, tc, &rc); + + /* we don't free anything here because RPC isn't complete */ + + return err; +} + /** * p9_free_req - free a request and clean-up as necessary * c: client state @@ -289,6 +322,224 @@ void p9_free_req(struct p9_client *c, struct p9_req_t *r) } } +/** + * p9_client_cb - call back from transport to client + * c: client state + * req: request received + * + */ +void p9_client_cb(struct p9_client *c, struct p9_req_t *req) +{ + struct p9_req_t *other_req; + unsigned long flags; + + P9_DPRINTK(P9_DEBUG_MUX, ": %d\n", req->tc->tag); + + if (req->status == REQ_STATUS_ERROR) + wake_up(req->wq); + + if (req->tc->id == P9_TFLUSH) { /* flush receive path */ + P9_DPRINTK(P9_DEBUG_MUX, "flush: %d\n", req->tc->tag); + spin_lock_irqsave(&c->lock, flags); + other_req = p9_tag_lookup(c, req->tc->params.tflush.oldtag); + if (other_req->flush_tag != req->tc->tag) /* stale flush */ + spin_unlock_irqrestore(&c->lock, flags); + else { + BUG_ON(other_req->status != REQ_STATUS_FLSH); + other_req->status = REQ_STATUS_FLSHD; + spin_unlock_irqrestore(&c->lock, flags); + wake_up(other_req->wq); + } + p9_free_req(c, req); + } else { /* normal receive path */ + P9_DPRINTK(P9_DEBUG_MUX, "normal: %d\n", req->tc->tag); + spin_lock_irqsave(&c->lock, flags); + if (req->status != REQ_STATUS_FLSHD) + req->status = REQ_STATUS_RCVD; + req->flush_tag = P9_NOTAG; + spin_unlock_irqrestore(&c->lock, flags); + wake_up(req->wq); + P9_DPRINTK(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag); + } +} +EXPORT_SYMBOL(p9_client_cb); + +/** + * p9_client_rpc - issue a request and wait for a response + * @c: client session + * @tc: &p9_fcall request to transmit + * @rc: &p9_fcall to put reponse into + * + * Returns 0 on success, error code on failure + */ + +static int +p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) +{ + int tag, err, size; + char *rdata; + struct p9_req_t *req; + unsigned long flags; + int sigpending; + int flushed = 0; + + P9_DPRINTK(P9_DEBUG_9P, "client %p tc %p rc %p\n", c, tc, rc); + + if (c->status != Connected) + return -EIO; + + if (signal_pending(current)) { + sigpending = 1; + clear_thread_flag(TIF_SIGPENDING); + } else + sigpending = 0; + + tag = P9_NOTAG; + if (tc->id != P9_TVERSION) { + tag = p9_idpool_get(c->tagpool); + if (tag < 0) + return -ENOMEM; + } + + req = p9_tag_alloc(c, tag); + + /* if this is a flush request, backlink flush request now to + * avoid race conditions later. */ + if (tc->id == P9_TFLUSH) { + struct p9_req_t *other_req = + p9_tag_lookup(c, tc->params.tflush.oldtag); + if (other_req->status == REQ_STATUS_FLSH) + other_req->flush_tag = tag; + } + + p9_set_tag(tc, tag); + + /* + * if client passed in a pre-allocated response fcall struct + * then we just use that, otherwise we allocate one. + */ + + if (rc == NULL) + req->rc = NULL; + else + req->rc = *rc; + if (req->rc == NULL) { + req->rc = kmalloc(sizeof(struct p9_fcall) + c->msize, + GFP_KERNEL); + if (!req->rc) { + err = -ENOMEM; + p9_idpool_put(tag, c->tagpool); + p9_free_req(c, req); + goto reterr; + } + *rc = req->rc; + } + + rdata = (char *)req->rc+sizeof(struct p9_fcall); + + req->tc = tc; + P9_DPRINTK(P9_DEBUG_9P, "request: tc: %p rc: %p\n", req->tc, req->rc); + + err = c->trans_mod->request(c, req); + if (err < 0) { + c->status = Disconnected; + goto reterr; + } + + /* if it was a flush we just transmitted, return our tag */ + if (tc->id == P9_TFLUSH) + return 0; +again: + P9_DPRINTK(P9_DEBUG_9P, "wait %p tag: %d\n", req->wq, tag); + err = wait_event_interruptible(*req->wq, + req->status >= REQ_STATUS_RCVD); + P9_DPRINTK(P9_DEBUG_9P, "wait %p tag: %d returned %d (flushed=%d)\n", + req->wq, tag, err, flushed); + + if (req->status == REQ_STATUS_ERROR) { + P9_DPRINTK(P9_DEBUG_9P, "req_status error %d\n", req->t_err); + err = req->t_err; + } else if (err == -ERESTARTSYS && flushed) { + P9_DPRINTK(P9_DEBUG_9P, "flushed - going again\n"); + goto again; + } else if (req->status == REQ_STATUS_FLSHD) { + P9_DPRINTK(P9_DEBUG_9P, "flushed - erestartsys\n"); + err = -ERESTARTSYS; + } + + if ((err == -ERESTARTSYS) && (c->status == Connected) && (!flushed)) { + P9_DPRINTK(P9_DEBUG_9P, "flushing\n"); + spin_lock_irqsave(&c->lock, flags); + if (req->status == REQ_STATUS_SENT) + req->status = REQ_STATUS_FLSH; + spin_unlock_irqrestore(&c->lock, flags); + sigpending = 1; + flushed = 1; + clear_thread_flag(TIF_SIGPENDING); + + if (c->trans_mod->cancel(c, req)) { + err = p9_client_flush(c, req); + if (err == 0) + goto again; + } + } + + if (sigpending) { + spin_lock_irqsave(¤t->sighand->siglock, flags); + recalc_sigpending(); + spin_unlock_irqrestore(¤t->sighand->siglock, flags); + } + + if (err < 0) + goto reterr; + + size = le32_to_cpu(*(__le32 *) rdata); + + err = p9_deserialize_fcall(rdata, size, req->rc, c->dotu); + if (err < 0) { + P9_DPRINTK(P9_DEBUG_9P, + "9p debug: client rpc deserialize returned %d\n", err); + goto reterr; + } + +#ifdef CONFIG_NET_9P_DEBUG + if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { + char buf[150]; + + p9_printfcall(buf, sizeof(buf), req->rc, c->dotu); + printk(KERN_NOTICE ">>> %p %s\n", c, buf); + } +#endif + + if (req->rc->id == P9_RERROR) { + int ecode = req->rc->params.rerror.errno; + struct p9_str *ename = &req->rc->params.rerror.error; + + P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len, + ename->str); + + if (c->dotu) + err = -ecode; + + if (!err) { + err = p9_errstr2errno(ename->str, ename->len); + + /* string match failed */ + if (!err) { + PRINT_FCALL_ERROR("unknown error", req->rc); + err = -ESERVERFAULT; + } + } + } else + err = 0; + +reterr: + p9_free_req(c, req); + + P9_DPRINTK(P9_DEBUG_9P, "returning %d\n", err); + return err; +} + static struct p9_fid *p9_fid_create(struct p9_client *clnt) { int err; @@ -339,20 +590,6 @@ static void p9_fid_destroy(struct p9_fid *fid) kfree(fid); } -/** - * p9_client_rpc - sends 9P request and waits until a response is available. - * The function can be interrupted. - * @c: client data - * @tc: request to be sent - * @rc: pointer where a pointer to the response is stored - */ -int -p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, - struct p9_fcall **rc) -{ - return c->trans_mod->rpc(c, tc, rc); -} - struct p9_client *p9_client_create(const char *dev_name, char *options) { int err, n; diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 627e3f097fc5..6bfc013f8b6f 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -174,44 +174,6 @@ static void p9_mux_poll_stop(struct p9_conn *m) spin_unlock_irqrestore(&p9_poll_lock, flags); } -static void p9_conn_rpc_cb(struct p9_client *, struct p9_req_t *); - -static void p9_mux_flush_cb(struct p9_client *client, struct p9_req_t *freq) -{ - struct p9_conn *m = client->trans; - struct p9_req_t *req; - - P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m, - freq->tc, freq->rc, freq->t_err, - freq->tc->params.tflush.oldtag); - - req = p9_tag_lookup(client, freq->tc->params.tflush.oldtag); - if (req) { - req->status = REQ_STATUS_FLSHD; - list_del(&req->req_list); - p9_conn_rpc_cb(client, req); - } - - p9_free_req(client, freq); -} - -static void p9_conn_rpc_cb(struct p9_client *client, struct p9_req_t *req) -{ - P9_DPRINTK(P9_DEBUG_MUX, "req %p\n", req); - - if (req->tc->id == P9_TFLUSH) { /* flush callback */ - P9_DPRINTK(P9_DEBUG_MUX, "flush req %p\n", req); - p9_mux_flush_cb(client, req); - } else { /* normal wakeup path */ - P9_DPRINTK(P9_DEBUG_MUX, "normal req %p\n", req); - if (!req->t_err && (req->status == REQ_STATUS_FLSHD || - req->status == REQ_STATUS_FLSH)) - req->t_err = -ERESTARTSYS; - - wake_up(req->wq); - } -} - /** * p9_conn_cancel - cancel all pending requests with error * @m: mux data @@ -222,11 +184,12 @@ static void p9_conn_rpc_cb(struct p9_client *client, struct p9_req_t *req) void p9_conn_cancel(struct p9_conn *m, int err) { struct p9_req_t *req, *rtmp; + unsigned long flags; LIST_HEAD(cancel_list); P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err); m->err = err; - spin_lock(&m->client->lock); + spin_lock_irqsave(&m->client->lock, flags); list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { req->status = REQ_STATUS_ERROR; if (!req->t_err) @@ -239,44 +202,12 @@ void p9_conn_cancel(struct p9_conn *m, int err) req->t_err = err; list_move(&req->req_list, &cancel_list); } - spin_unlock(&m->client->lock); + spin_unlock_irqrestore(&m->client->lock, flags); list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { list_del(&req->req_list); - p9_conn_rpc_cb(m->client, req); - } -} - -static void process_request(struct p9_conn *m, struct p9_req_t *req) -{ - int ecode; - struct p9_str *ename; - - if (!req->t_err && req->rc->id == P9_RERROR) { - ecode = req->rc->params.rerror.errno; - ename = &req->rc->params.rerror.error; - - P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len, - ename->str); - - if (m->client->dotu) - req->t_err = -ecode; - - if (!req->t_err) { - req->t_err = p9_errstr2errno(ename->str, ename->len); - - /* string match failed */ - if (!req->t_err) { - PRINT_FCALL_ERROR("unknown error", req->rc); - req->t_err = -ESERVERFAULT; - } - } - } else if (req->tc && req->rc->id != req->tc->id + 1) { - P9_DPRINTK(P9_DEBUG_ERROR, - "fcall mismatch: expected %d, got %d\n", - req->tc->id + 1, req->rc->id); - if (!req->t_err) - req->t_err = -EIO; + P9_DPRINTK(P9_DEBUG_ERROR, "call back req %p\n", req); + p9_client_cb(m->client, req); } } @@ -421,41 +352,13 @@ static void p9_read_work(struct work_struct *work) /* not an else because some packets (like clunk) have no payload */ if ((m->req) && (m->rpos == m->rsize)) { /* packet is read in */ P9_DPRINTK(P9_DEBUG_MUX, "got new packet\n"); - m->rbuf = (char *)m->req->rc + sizeof(struct p9_fcall); - err = p9_deserialize_fcall(m->rbuf, m->rsize, m->req->rc, - m->client->dotu); - if (err < 0) { - m->req = NULL; - goto error; - } - -#ifdef CONFIG_NET_9P_DEBUG - if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { - char buf[150]; - - p9_printfcall(buf, sizeof(buf), m->req->rc, - m->client->dotu); - printk(KERN_NOTICE ">>> %p %s\n", m, buf); - } -#endif - P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, - m->req->rc->id, m->req->rc->tag); + list_del(&m->req->req_list); + p9_client_cb(m->client, m->req); m->rbuf = NULL; m->rpos = 0; m->rsize = 0; - - if (m->req->status != REQ_STATUS_FLSH) { - list_del(&m->req->req_list); - m->req->status = REQ_STATUS_RCVD; - } - - process_request(m, m->req); - - if (m->req->status != REQ_STATUS_FLSH) - p9_conn_rpc_cb(m->client, m->req); - m->req = NULL; } @@ -741,57 +644,41 @@ static void p9_poll_mux(struct p9_conn *m) } /** - * p9_send_request - send 9P request + * p9_fd_request - send 9P request * The function can sleep until the request is scheduled for sending. * The function can be interrupted. Return from the function is not - * a guarantee that the request is sent successfully. Can return errors - * that can be retrieved by PTR_ERR macros. + * a guarantee that the request is sent successfully. * - * @m: mux data - * @tc: request to be sent + * @client: client instance + * @req: request to be sent * */ -static struct p9_req_t *p9_send_request(struct p9_conn *m, struct p9_fcall *tc) +static int p9_fd_request(struct p9_client *client, struct p9_req_t *req) { - int tag; int n; - struct p9_req_t *req; + struct p9_trans_fd *ts = client->trans; + struct p9_conn *m = ts->conn; P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current, - tc, tc->id); + req->tc, req->tc->id); if (m->err < 0) - return ERR_PTR(m->err); - - tag = P9_NOTAG; - if (tc->id != P9_TVERSION) { - tag = p9_idpool_get(m->client->tagpool); - if (tag < 0) - return ERR_PTR(-ENOMEM); - } - - p9_set_tag(tc, tag); - - req = p9_tag_alloc(m->client, tag); + return m->err; #ifdef CONFIG_NET_9P_DEBUG if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { char buf[150]; - p9_printfcall(buf, sizeof(buf), tc, m->client->dotu); + p9_printfcall(buf, sizeof(buf), req->tc, client->dotu); printk(KERN_NOTICE "<<< %p %s\n", m, buf); } #endif - req->tag = tag; - req->tc = tc; - req->rc = NULL; - req->t_err = 0; req->status = REQ_STATUS_UNSENT; - spin_lock(&m->client->lock); + spin_lock(&client->lock); list_add_tail(&req->req_list, &m->unsent_req_list); - spin_unlock(&m->client->lock); + spin_unlock(&client->lock); if (test_and_clear_bit(Wpending, &m->wsched)) n = POLLOUT; @@ -801,17 +688,20 @@ static struct p9_req_t *p9_send_request(struct p9_conn *m, struct p9_fcall *tc) if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched)) queue_work(p9_mux_wq, &m->wq); - return req; + return 0; } -static int -p9_mux_flush_request(struct p9_conn *m, struct p9_req_t *req) +static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req) { - struct p9_fcall *fc; - struct p9_req_t *rreq, *rptr; + struct p9_trans_fd *ts = client->trans; + struct p9_conn *m = ts->conn; P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag); + spin_lock(&client->lock); + list_del(&req->req_list); + spin_unlock(&client->lock); + /* if a response was received for a request, do nothing */ if (req->rc || req->t_err) { P9_DPRINTK(P9_DEBUG_MUX, @@ -819,103 +709,14 @@ p9_mux_flush_request(struct p9_conn *m, struct p9_req_t *req) return 0; } - req->status = REQ_STATUS_FLSH; - - spin_lock(&m->client->lock); - /* if the request is not sent yet, just remove it from the list */ - list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) { - if (rreq->tag == req->tag) { - P9_DPRINTK(P9_DEBUG_MUX, - "mux %p req %p request is not sent yet\n", m, req); - list_del(&rreq->req_list); - req->status = REQ_STATUS_FLSHD; - spin_unlock(&m->client->lock); - p9_conn_rpc_cb(m->client, req); - return 0; - } + if (req->status == REQ_STATUS_UNSENT) { + req->status = REQ_STATUS_FLSHD; + return 0; } - spin_unlock(&m->client->lock); - clear_thread_flag(TIF_SIGPENDING); - fc = p9_create_tflush(req->tag); - p9_send_request(m, fc); return 1; } -/** - * p9_fd_rpc- sends 9P request and waits until a response is available. - * The function can be interrupted. - * @client: client instance - * @tc: request to be sent - * @rc: pointer where a pointer to the response is stored - * - */ - -int -p9_fd_rpc(struct p9_client *client, struct p9_fcall *tc, struct p9_fcall **rc) -{ - struct p9_trans_fd *p = client->trans; - struct p9_conn *m = p->conn; - int err, sigpending; - unsigned long flags; - struct p9_req_t *req; - - if (rc) - *rc = NULL; - - sigpending = 0; - if (signal_pending(current)) { - sigpending = 1; - clear_thread_flag(TIF_SIGPENDING); - } - - req = p9_send_request(m, tc); - if (IS_ERR(req)) { - err = PTR_ERR(req); - P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err); - return err; - } - - err = wait_event_interruptible(*req->wq, req->rc != NULL || - req->t_err < 0); - if (req->t_err < 0) - err = req->t_err; - - if (err == -ERESTARTSYS && client->status == Connected - && m->err == 0) { - if (p9_mux_flush_request(m, req)) { - /* wait until we get response of the flush message */ - do { - clear_thread_flag(TIF_SIGPENDING); - err = wait_event_interruptible(*req->wq, - req->rc || req->t_err); - } while (!req->rc && !req->t_err && - err == -ERESTARTSYS && - client->status == Connected && !m->err); - - err = -ERESTARTSYS; - } - sigpending = 1; - } - - if (sigpending) { - spin_lock_irqsave(¤t->sighand->siglock, flags); - recalc_sigpending(); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); - } - - if (rc) - *rc = req->rc; - else - kfree(req->rc); - - p9_free_req(client, req); - if (err > 0) - err = -EIO; - - return err; -} - /** * parse_options - parse mount options into session structure * @options: options string passed from mount @@ -1243,7 +1044,8 @@ static struct p9_trans_module p9_tcp_trans = { .def = 1, .create = p9_fd_create_tcp, .close = p9_fd_close, - .rpc = p9_fd_rpc, + .request = p9_fd_request, + .cancel = p9_fd_cancel, .owner = THIS_MODULE, }; @@ -1253,7 +1055,8 @@ static struct p9_trans_module p9_unix_trans = { .def = 0, .create = p9_fd_create_unix, .close = p9_fd_close, - .rpc = p9_fd_rpc, + .request = p9_fd_request, + .cancel = p9_fd_cancel, .owner = THIS_MODULE, }; @@ -1263,7 +1066,8 @@ static struct p9_trans_module p9_fd_trans = { .def = 0, .create = p9_fd_create, .close = p9_fd_close, - .rpc = p9_fd_rpc, + .request = p9_fd_request, + .cancel = p9_fd_cancel, .owner = THIS_MODULE, }; diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index e18de14c30d5..2d7781ec663b 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -126,17 +126,16 @@ static void req_done(struct virtqueue *vq) struct virtio_chan *chan = vq->vdev->priv; struct p9_fcall *rc; unsigned int len; - unsigned long flags; struct p9_req_t *req; - spin_lock_irqsave(&chan->lock, flags); + P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n"); + while ((rc = chan->vq->vq_ops->get_buf(chan->vq, &len)) != NULL) { + P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc); + P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag); req = p9_tag_lookup(chan->client, rc->tag); - req->status = REQ_STATUS_RCVD; - wake_up(req->wq); + p9_client_cb(chan->client, req); } - /* In case queue is stopped waiting for more buffers. */ - spin_unlock_irqrestore(&chan->lock, flags); } /** @@ -173,8 +172,14 @@ pack_sg_list(struct scatterlist *sg, int start, int limit, char *data, return index-start; } +/* We don't currently allow canceling of virtio requests */ +static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req) +{ + return 1; +} + /** - * p9_virtio_rpc - issue a request and wait for a response + * p9_virtio_request - issue a request * @t: transport state * @tc: &p9_fcall request to transmit * @rc: &p9_fcall to put reponse into @@ -182,44 +187,22 @@ pack_sg_list(struct scatterlist *sg, int start, int limit, char *data, */ static int -p9_virtio_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) +p9_virtio_request(struct p9_client *client, struct p9_req_t *req) { int in, out; - int n, err, size; - struct virtio_chan *chan = c->trans; - char *rdata; - struct p9_req_t *req; - unsigned long flags; - - if (*rc == NULL) { - *rc = kmalloc(sizeof(struct p9_fcall) + c->msize, GFP_KERNEL); - if (!*rc) - return -ENOMEM; - } - - rdata = (char *)*rc+sizeof(struct p9_fcall); - - n = P9_NOTAG; - if (tc->id != P9_TVERSION) { - n = p9_idpool_get(c->tagpool); - if (n < 0) - return -ENOMEM; - } - - spin_lock_irqsave(&chan->lock, flags); - req = p9_tag_alloc(c, n); - spin_unlock_irqrestore(&chan->lock, flags); - - p9_set_tag(tc, n); + struct virtio_chan *chan = client->trans; + char *rdata = (char *)req->rc+sizeof(struct p9_fcall); - P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio rpc tag %d\n", n); + P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); - out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, tc->sdata, tc->size); - in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, c->msize); + out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata, + req->tc->size); + in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, + client->msize); req->status = REQ_STATUS_SENT; - if (chan->vq->vq_ops->add_buf(chan->vq, chan->sg, out, in, tc)) { + if (chan->vq->vq_ops->add_buf(chan->vq, chan->sg, out, in, req->tc)) { P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio rpc add_buf returned failure"); return -EIO; @@ -227,28 +210,7 @@ p9_virtio_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) chan->vq->vq_ops->kick(chan->vq); - wait_event(*req->wq, req->status == REQ_STATUS_RCVD); - - size = le32_to_cpu(*(__le32 *) rdata); - - err = p9_deserialize_fcall(rdata, size, *rc, c->dotu); - if (err < 0) { - P9_DPRINTK(P9_DEBUG_TRANS, - "9p debug: virtio rpc deserialize returned %d\n", err); - return err; - } - -#ifdef CONFIG_NET_9P_DEBUG - if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { - char buf[150]; - - p9_printfcall(buf, sizeof(buf), *rc, c->dotu); - printk(KERN_NOTICE ">>> %p %s\n", c, buf); - } -#endif - - p9_free_req(c, req); - + P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n"); return 0; } @@ -394,7 +356,8 @@ static struct p9_trans_module p9_virtio_trans = { .name = "virtio", .create = p9_virtio_create, .close = p9_virtio_close, - .rpc = p9_virtio_rpc, + .request = p9_virtio_request, + .cancel = p9_virtio_cancel, .maxsize = PAGE_SIZE*16, .def = 0, .owner = THIS_MODULE, -- cgit v1.2.3 From 95820a36516d12dcb49d066dd3d5b187a2557612 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 13 Oct 2008 18:45:20 -0500 Subject: 9p: drop broken unused error path from p9_conn_create() Post p9_fd_poll() error path which checks m->poll_waddr[i] for PTR_ERR value has the following problems. * It's completely unused. Error value is set iff NULL @wait_address has been specified to p9_pollwait() which is guaranteed not to happen. * It dereferences @m after deallocating it (introduced by 571ffeaf and spotted by Raja R Harinath. * It returned the wrong value on error. It should return poll_waddr[i] but it returnes poll_waddr (introduced by 571ffeaf). * p9_mux_poll_stop() doesn't handle PTR_ERR value. It will try to operate on the PTR_ERR value as if it's a normal pointer and cause oops. As the error path is bogus in the first place, there's no reason to hold onto it. Kill it. Signed-off-by: Tejun Heo Signed-off-by: Eric Van Hensbergen Cc: Raja R Harinath --- net/9p/trans_fd.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) (limited to 'net/9p/trans_fd.c') diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 6bfc013f8b6f..c07f2ab8d0f7 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -540,12 +540,6 @@ p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) return; } - if (!wait_address) { - P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n"); - pwait->wait_addr = ERR_PTR(-EIO); - return; - } - pwait->conn = m; pwait->wait_addr = wait_address; init_waitqueue_func_entry(&pwait->wait, p9_pollwake); @@ -561,7 +555,7 @@ p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) static struct p9_conn *p9_conn_create(struct p9_client *client) { - int i, n; + int n; struct p9_conn *m; P9_DPRINTK(P9_DEBUG_MUX, "client %p msize %d\n", client, client->msize); @@ -590,15 +584,6 @@ static struct p9_conn *p9_conn_create(struct p9_client *client) set_bit(Wpending, &m->wsched); } - for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { - if (IS_ERR(m->poll_wait[i].wait_addr)) { - p9_mux_poll_stop(m); - kfree(m); - /* return the error code */ - return (void *)m->poll_wait[i].wait_addr; - } - } - return m; } -- cgit v1.2.3 From 51d71f9f7a639c8a39401de1ec5ce9b0b6476c99 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Thu, 16 Oct 2008 08:29:31 -0500 Subject: 9p: remove 9p fcall debug prints One of the current debug options allows users to get a verbose dump of fcalls. This isn't really necessary as correctly parsed protocol frames can be printed as part of the code in the client functions. The consolidated printfcalls structure would require new entries to be added for every extension. This patch removes the debug print methods and their use. Signed-off-by: Eric Van Hensbergen --- include/net/9p/9p.h | 1 - net/9p/Makefile | 1 - net/9p/client.c | 9 -- net/9p/fcprint.c | 366 ---------------------------------------------------- net/9p/trans_fd.c | 9 -- 5 files changed, 386 deletions(-) delete mode 100644 net/9p/fcprint.c (limited to 'net/9p/trans_fd.c') diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index f9e25268b70f..46d0b8f8e5ec 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h @@ -590,7 +590,6 @@ struct p9_fcall *p9_create_tstat(u32 fid); struct p9_fcall *p9_create_twstat(u32 fid, struct p9_wstat *wstat, int dotu); -int p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int dotu); int p9_errstr2errno(char *errstr, int len); struct p9_idpool *p9_idpool_create(void); diff --git a/net/9p/Makefile b/net/9p/Makefile index 84c23499a293..c3302d88b808 100644 --- a/net/9p/Makefile +++ b/net/9p/Makefile @@ -6,7 +6,6 @@ obj-$(CONFIG_NET_9P_VIRTIO) += 9pnet_virtio.o client.o \ conv.o \ error.o \ - fcprint.o \ util.o \ protocol.o \ trans_fd.o \ diff --git a/net/9p/client.c b/net/9p/client.c index a9982df00a3a..6004fded6682 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -502,15 +502,6 @@ again: goto reterr; } -#ifdef CONFIG_NET_9P_DEBUG - if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { - char buf[150]; - - p9_printfcall(buf, sizeof(buf), req->rc, c->dotu); - printk(KERN_NOTICE ">>> %p %s\n", c, buf); - } -#endif - if (req->rc->id == P9_RERROR) { int ecode = req->rc->params.rerror.errno; struct p9_str *ename = &req->rc->params.rerror.error; diff --git a/net/9p/fcprint.c b/net/9p/fcprint.c deleted file mode 100644 index 53dd8e28dd8a..000000000000 --- a/net/9p/fcprint.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - * net/9p/fcprint.c - * - * Print 9P call. - * - * Copyright (C) 2005 by Latchesar Ionkov - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to: - * Free Software Foundation - * 51 Franklin Street, Fifth Floor - * Boston, MA 02111-1301 USA - * - */ -#include -#include -#include -#include -#include - -#ifdef CONFIG_NET_9P_DEBUG - -static int -p9_printqid(char *buf, int buflen, struct p9_qid *q) -{ - int n; - char b[10]; - - n = 0; - if (q->type & P9_QTDIR) - b[n++] = 'd'; - if (q->type & P9_QTAPPEND) - b[n++] = 'a'; - if (q->type & P9_QTAUTH) - b[n++] = 'A'; - if (q->type & P9_QTEXCL) - b[n++] = 'l'; - if (q->type & P9_QTTMP) - b[n++] = 't'; - if (q->type & P9_QTSYMLINK) - b[n++] = 'L'; - b[n] = '\0'; - - return scnprintf(buf, buflen, "(%.16llx %x %s)", - (long long int) q->path, q->version, b); -} - -static int -p9_printperm(char *buf, int buflen, int perm) -{ - int n; - char b[15]; - - n = 0; - if (perm & P9_DMDIR) - b[n++] = 'd'; - if (perm & P9_DMAPPEND) - b[n++] = 'a'; - if (perm & P9_DMAUTH) - b[n++] = 'A'; - if (perm & P9_DMEXCL) - b[n++] = 'l'; - if (perm & P9_DMTMP) - b[n++] = 't'; - if (perm & P9_DMDEVICE) - b[n++] = 'D'; - if (perm & P9_DMSOCKET) - b[n++] = 'S'; - if (perm & P9_DMNAMEDPIPE) - b[n++] = 'P'; - if (perm & P9_DMSYMLINK) - b[n++] = 'L'; - b[n] = '\0'; - - return scnprintf(buf, buflen, "%s%03o", b, perm&077); -} - -static int -p9_printstat(char *buf, int buflen, struct p9_stat *st, int extended) -{ - int n; - - n = scnprintf(buf, buflen, "'%.*s' '%.*s'", st->name.len, - st->name.str, st->uid.len, st->uid.str); - if (extended) - n += scnprintf(buf+n, buflen-n, "(%d)", st->n_uid); - - n += scnprintf(buf+n, buflen-n, " '%.*s'", st->gid.len, st->gid.str); - if (extended) - n += scnprintf(buf+n, buflen-n, "(%d)", st->n_gid); - - n += scnprintf(buf+n, buflen-n, " '%.*s'", st->muid.len, st->muid.str); - if (extended) - n += scnprintf(buf+n, buflen-n, "(%d)", st->n_muid); - - n += scnprintf(buf+n, buflen-n, " q "); - n += p9_printqid(buf+n, buflen-n, &st->qid); - n += scnprintf(buf+n, buflen-n, " m "); - n += p9_printperm(buf+n, buflen-n, st->mode); - n += scnprintf(buf+n, buflen-n, " at %d mt %d l %lld", - st->atime, st->mtime, (long long int) st->length); - - if (extended) - n += scnprintf(buf+n, buflen-n, " ext '%.*s'", - st->extension.len, st->extension.str); - - return n; -} - -static int -p9_dumpdata(char *buf, int buflen, u8 *data, int datalen) -{ - int i, n; - - i = n = 0; - while (i < datalen) { - n += scnprintf(buf + n, buflen - n, "%02x", data[i]); - if (i%4 == 3) - n += scnprintf(buf + n, buflen - n, " "); - if (i%32 == 31) - n += scnprintf(buf + n, buflen - n, "\n"); - - i++; - } - n += scnprintf(buf + n, buflen - n, "\n"); - - return n; -} - -static int -p9_printdata(char *buf, int buflen, u8 *data, int datalen) -{ - return p9_dumpdata(buf, buflen, data, datalen < 16?datalen:16); -} - -/** - * p9_printfcall - decode and print a protocol structure into a buffer - * @buf: buffer to deposit decoded structure into - * @buflen: available space in buffer - * @fc: protocol rpc structure of type &p9_fcall - * @extended: whether or not session is operating with extended protocol - */ - -int -p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended) -{ - int i, ret, type, tag; - - if (!fc) - return scnprintf(buf, buflen, ""); - - type = fc->id; - tag = fc->tag; - - ret = 0; - switch (type) { - case P9_TVERSION: - ret += scnprintf(buf+ret, buflen-ret, - "Tversion tag %u msize %u version '%.*s'", tag, - fc->params.tversion.msize, - fc->params.tversion.version.len, - fc->params.tversion.version.str); - break; - - case P9_RVERSION: - ret += scnprintf(buf+ret, buflen-ret, - "Rversion tag %u msize %u version '%.*s'", tag, - fc->params.rversion.msize, - fc->params.rversion.version.len, - fc->params.rversion.version.str); - break; - - case P9_TAUTH: - ret += scnprintf(buf+ret, buflen-ret, - "Tauth tag %u afid %d uname '%.*s' aname '%.*s'", tag, - fc->params.tauth.afid, fc->params.tauth.uname.len, - fc->params.tauth.uname.str, fc->params.tauth.aname.len, - fc->params.tauth.aname.str); - break; - - case P9_RAUTH: - ret += scnprintf(buf+ret, buflen-ret, "Rauth tag %u qid ", tag); - p9_printqid(buf+ret, buflen-ret, &fc->params.rauth.qid); - break; - - case P9_TATTACH: - ret += scnprintf(buf+ret, buflen-ret, - "Tattach tag %u fid %d afid %d uname '%.*s' aname '%.*s'", tag, - fc->params.tattach.fid, fc->params.tattach.afid, - fc->params.tattach.uname.len, fc->params.tattach.uname.str, - fc->params.tattach.aname.len, fc->params.tattach.aname.str); - break; - - case P9_RATTACH: - ret += scnprintf(buf+ret, buflen-ret, "Rattach tag %u qid ", - tag); - p9_printqid(buf+ret, buflen-ret, &fc->params.rattach.qid); - break; - - case P9_RERROR: - ret += scnprintf(buf+ret, buflen-ret, - "Rerror tag %u ename '%.*s'", tag, - fc->params.rerror.error.len, - fc->params.rerror.error.str); - if (extended) - ret += scnprintf(buf+ret, buflen-ret, " ecode %d\n", - fc->params.rerror.errno); - break; - - case P9_TFLUSH: - ret += scnprintf(buf+ret, buflen-ret, "Tflush tag %u oldtag %u", - tag, fc->params.tflush.oldtag); - break; - - case P9_RFLUSH: - ret += scnprintf(buf+ret, buflen-ret, "Rflush tag %u", tag); - break; - - case P9_TWALK: - ret += scnprintf(buf+ret, buflen-ret, - "Twalk tag %u fid %d newfid %d nwname %d", tag, - fc->params.twalk.fid, fc->params.twalk.newfid, - fc->params.twalk.nwname); - for (i = 0; i < fc->params.twalk.nwname; i++) - ret += scnprintf(buf+ret, buflen-ret, " '%.*s'", - fc->params.twalk.wnames[i].len, - fc->params.twalk.wnames[i].str); - break; - - case P9_RWALK: - ret += scnprintf(buf+ret, buflen-ret, "Rwalk tag %u nwqid %d", - tag, fc->params.rwalk.nwqid); - for (i = 0; i < fc->params.rwalk.nwqid; i++) - ret += p9_printqid(buf+ret, buflen-ret, - &fc->params.rwalk.wqids[i]); - break; - - case P9_TOPEN: - ret += scnprintf(buf+ret, buflen-ret, - "Topen tag %u fid %d mode %d", tag, - fc->params.topen.fid, fc->params.topen.mode); - break; - - case P9_ROPEN: - ret += scnprintf(buf+ret, buflen-ret, "Ropen tag %u", tag); - ret += p9_printqid(buf+ret, buflen-ret, &fc->params.ropen.qid); - ret += scnprintf(buf+ret, buflen-ret, " iounit %d", - fc->params.ropen.iounit); - break; - - case P9_TCREATE: - ret += scnprintf(buf+ret, buflen-ret, - "Tcreate tag %u fid %d name '%.*s' perm ", tag, - fc->params.tcreate.fid, fc->params.tcreate.name.len, - fc->params.tcreate.name.str); - - ret += p9_printperm(buf+ret, buflen-ret, - fc->params.tcreate.perm); - ret += scnprintf(buf+ret, buflen-ret, " mode %d", - fc->params.tcreate.mode); - break; - - case P9_RCREATE: - ret += scnprintf(buf+ret, buflen-ret, "Rcreate tag %u", tag); - ret += p9_printqid(buf+ret, buflen-ret, - &fc->params.rcreate.qid); - ret += scnprintf(buf+ret, buflen-ret, " iounit %d", - fc->params.rcreate.iounit); - break; - - case P9_TREAD: - ret += scnprintf(buf+ret, buflen-ret, - "Tread tag %u fid %d offset %lld count %u", tag, - fc->params.tread.fid, - (long long int) fc->params.tread.offset, - fc->params.tread.count); - break; - - case P9_RREAD: - ret += scnprintf(buf+ret, buflen-ret, - "Rread tag %u count %u data ", tag, - fc->params.rread.count); - ret += p9_printdata(buf+ret, buflen-ret, fc->params.rread.data, - fc->params.rread.count); - break; - - case P9_TWRITE: - ret += scnprintf(buf+ret, buflen-ret, - "Twrite tag %u fid %d offset %lld count %u data ", - tag, fc->params.twrite.fid, - (long long int) fc->params.twrite.offset, - fc->params.twrite.count); - ret += p9_printdata(buf+ret, buflen-ret, fc->params.twrite.data, - fc->params.twrite.count); - break; - - case P9_RWRITE: - ret += scnprintf(buf+ret, buflen-ret, "Rwrite tag %u count %u", - tag, fc->params.rwrite.count); - break; - - case P9_TCLUNK: - ret += scnprintf(buf+ret, buflen-ret, "Tclunk tag %u fid %d", - tag, fc->params.tclunk.fid); - break; - - case P9_RCLUNK: - ret += scnprintf(buf+ret, buflen-ret, "Rclunk tag %u", tag); - break; - - case P9_TREMOVE: - ret += scnprintf(buf+ret, buflen-ret, "Tremove tag %u fid %d", - tag, fc->params.tremove.fid); - break; - - case P9_RREMOVE: - ret += scnprintf(buf+ret, buflen-ret, "Rremove tag %u", tag); - break; - - case P9_TSTAT: - ret += scnprintf(buf+ret, buflen-ret, "Tstat tag %u fid %d", - tag, fc->params.tstat.fid); - break; - - case P9_RSTAT: - ret += scnprintf(buf+ret, buflen-ret, "Rstat tag %u ", tag); - ret += p9_printstat(buf+ret, buflen-ret, &fc->params.rstat.stat, - extended); - break; - - case P9_TWSTAT: - ret += scnprintf(buf+ret, buflen-ret, "Twstat tag %u fid %d ", - tag, fc->params.twstat.fid); - ret += p9_printstat(buf+ret, buflen-ret, - &fc->params.twstat.stat, extended); - break; - - case P9_RWSTAT: - ret += scnprintf(buf+ret, buflen-ret, "Rwstat tag %u", tag); - break; - - default: - ret += scnprintf(buf+ret, buflen-ret, "unknown type %d", type); - break; - } - - return ret; -} -#else -int -p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended) -{ - return 0; -} -#endif /* CONFIG_NET_9P_DEBUG */ -EXPORT_SYMBOL(p9_printfcall); - diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index c07f2ab8d0f7..95c9b949d1a5 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -650,15 +650,6 @@ static int p9_fd_request(struct p9_client *client, struct p9_req_t *req) if (m->err < 0) return m->err; -#ifdef CONFIG_NET_9P_DEBUG - if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { - char buf[150]; - - p9_printfcall(buf, sizeof(buf), req->tc, client->dotu); - printk(KERN_NOTICE "<<< %p %s\n", m, buf); - } -#endif - req->status = REQ_STATUS_UNSENT; spin_lock(&client->lock); -- cgit v1.2.3 From cb198131b0e7aba755ac164744536d461e86ab82 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Thu, 16 Oct 2008 08:29:31 -0500 Subject: 9p: remove unnecessary tag field from p9_req_t structure This removes the vestigial tag field from the p9_req_t structure. Signed-off-by: Eric Van Hensbergen --- include/net/9p/client.h | 2 -- net/9p/trans_fd.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'net/9p/trans_fd.c') diff --git a/include/net/9p/client.h b/include/net/9p/client.h index eeb7d922816e..475ef5cf1644 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -81,7 +81,6 @@ enum p9_req_status_t { * @tc: the request fcall structure * @rc: the response fcall structure * @aux: transport specific data (provided for trans_fd migration) - * @tag: tag on request (BUG: redundant) * @req_list: link for higher level objects to chain requests * * Transport use an array to track outstanding requests @@ -104,7 +103,6 @@ struct p9_req_t { u16 flush_tag; void *aux; - int tag; struct list_head req_list; }; diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 95c9b949d1a5..e147ec539585 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -672,7 +672,7 @@ static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req) struct p9_trans_fd *ts = client->trans; struct p9_conn *m = ts->conn; - P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag); + P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p\n", m, req); spin_lock(&client->lock); list_del(&req->req_list); -- cgit v1.2.3 From 51a87c552dfd428e304c865e24ecbe091556f226 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Thu, 16 Oct 2008 08:30:07 -0500 Subject: 9p: rework client code to use new protocol support functions Now that the new protocol functions are in place, this patch switches the client code to using the new support code. Signed-off-by: Eric Van Hensbergen --- fs/9p/v9fs_vfs.h | 4 +- fs/9p/vfs_dir.c | 4 +- fs/9p/vfs_file.c | 2 +- fs/9p/vfs_inode.c | 38 +- fs/9p/vfs_super.c | 6 +- include/net/9p/9p.h | 7 +- include/net/9p/client.h | 7 +- net/9p/client.c | 931 +++++++++++++++++++++++------------------------- net/9p/protocol.c | 85 ++++- net/9p/protocol.h | 5 +- net/9p/trans_fd.c | 62 ++-- net/9p/util.c | 4 + 12 files changed, 611 insertions(+), 544 deletions(-) (limited to 'net/9p/trans_fd.c') diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index 046cff377f10..c295ba786edd 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h @@ -46,10 +46,10 @@ extern struct dentry_operations v9fs_cached_dentry_operations; struct inode *v9fs_get_inode(struct super_block *sb, int mode); ino_t v9fs_qid2ino(struct p9_qid *qid); -void v9fs_stat2inode(struct p9_stat *, struct inode *, struct super_block *); +void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *); int v9fs_dir_release(struct inode *inode, struct file *filp); int v9fs_file_open(struct inode *inode, struct file *file); -void v9fs_inode2stat(struct inode *inode, struct p9_stat *stat); +void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat); void v9fs_dentry_release(struct dentry *); int v9fs_uflags2omode(int uflags, int extended); diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index d7d0ac5a2ca3..276aed625929 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -85,8 +85,8 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) return -ENOMEM; while (1) { - err = v9fs_file_readn(filp, statbuf, NULL, fid->rdir_fpos, - buflen); + err = v9fs_file_readn(filp, statbuf, NULL, buflen, + fid->rdir_fpos); if (err <= 0) break; diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 3fd28bbafc87..041c52692284 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -136,7 +136,7 @@ v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count, int n, total; struct p9_fid *fid = filp->private_data; - P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, + P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid, (long long unsigned) offset, count); n = 0; diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index e83aa5ebe861..e96d84aafbe2 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -334,7 +334,7 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, { int err, umode; struct inode *ret; - struct p9_stat *st; + struct p9_wstat *st; ret = NULL; st = p9_client_stat(fid); @@ -417,6 +417,8 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, struct p9_fid *dfid, *ofid, *fid; struct inode *inode; + P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name); + err = 0; ofid = NULL; fid = NULL; @@ -424,6 +426,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, dfid = v9fs_fid_clone(dentry->d_parent); if (IS_ERR(dfid)) { err = PTR_ERR(dfid); + P9_DPRINTK(P9_DEBUG_VFS, "fid clone failed %d\n", err); dfid = NULL; goto error; } @@ -432,18 +435,22 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, ofid = p9_client_walk(dfid, 0, NULL, 1); if (IS_ERR(ofid)) { err = PTR_ERR(ofid); + P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); ofid = NULL; goto error; } err = p9_client_fcreate(ofid, name, perm, mode, extension); - if (err < 0) + if (err < 0) { + P9_DPRINTK(P9_DEBUG_VFS, "p9_client_fcreate failed %d\n", err); goto error; + } /* now walk from the parent so we can get unopened fid */ fid = p9_client_walk(dfid, 1, &name, 0); if (IS_ERR(fid)) { err = PTR_ERR(fid); + P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); fid = NULL; goto error; } else @@ -453,6 +460,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); if (IS_ERR(inode)) { err = PTR_ERR(inode); + P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); goto error; } @@ -734,7 +742,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, int err; struct v9fs_session_info *v9ses; struct p9_fid *fid; - struct p9_stat *st; + struct p9_wstat *st; P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); err = -EPERM; @@ -815,10 +823,9 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) */ void -v9fs_stat2inode(struct p9_stat *stat, struct inode *inode, +v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, struct super_block *sb) { - int n; char ext[32]; struct v9fs_session_info *v9ses = sb->s_fs_info; @@ -842,11 +849,7 @@ v9fs_stat2inode(struct p9_stat *stat, struct inode *inode, int major = -1; int minor = -1; - n = stat->extension.len; - if (n > sizeof(ext)-1) - n = sizeof(ext)-1; - memmove(ext, stat->extension.str, n); - ext[n] = 0; + strncpy(ext, stat->extension, sizeof(ext)); sscanf(ext, "%c %u %u", &type, &major, &minor); switch (type) { case 'c': @@ -857,8 +860,8 @@ v9fs_stat2inode(struct p9_stat *stat, struct inode *inode, break; default: P9_DPRINTK(P9_DEBUG_ERROR, - "Unknown special type %c (%.*s)\n", type, - stat->extension.len, stat->extension.str); + "Unknown special type %c %s\n", type, + stat->extension); }; inode->i_rdev = MKDEV(major, minor); } else @@ -904,7 +907,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) struct v9fs_session_info *v9ses; struct p9_fid *fid; - struct p9_stat *st; + struct p9_wstat *st; P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name); retval = -EPERM; @@ -926,15 +929,10 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) } /* copy extension buffer into buffer */ - if (st->extension.len < buflen) - buflen = st->extension.len + 1; - - memmove(buffer, st->extension.str, buflen - 1); - buffer[buflen-1] = 0; + strncpy(buffer, st->extension, buflen); P9_DPRINTK(P9_DEBUG_VFS, - "%s -> %.*s (%s)\n", dentry->d_name.name, st->extension.len, - st->extension.str, buffer); + "%s -> %s (%s)\n", dentry->d_name.name, st->extension, buffer); retval = buflen; diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index bf59c3960494..d6cb1a0ca724 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -111,7 +111,7 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, struct inode *inode = NULL; struct dentry *root = NULL; struct v9fs_session_info *v9ses = NULL; - struct p9_stat *st = NULL; + struct p9_wstat *st = NULL; int mode = S_IRWXUGO | S_ISVTX; uid_t uid = current->fsuid; gid_t gid = current->fsgid; @@ -161,10 +161,14 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, sb->s_root = root; root->d_inode->i_ino = v9fs_qid2ino(&st->qid); + v9fs_stat2inode(st, root->d_inode, sb); + v9fs_fid_add(root, fid); + p9stat_free(st); kfree(st); +P9_DPRINTK(P9_DEBUG_VFS, " return simple set mount\n"); return simple_set_mnt(mnt, sb); release_sb: diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index 46d0b8f8e5ec..56c15aee6e61 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h @@ -39,6 +39,7 @@ * @P9_DEBUG_TRANS: transport tracing * @P9_DEBUG_SLABS: memory management tracing * @P9_DEBUG_FCALL: verbose dump of protocol messages + * @P9_DEBUG_FID: fid allocation/deallocation tracking * * These flags are passed at mount time to turn on various levels of * verbosity and tracing which will be output to the system logs. @@ -53,13 +54,17 @@ enum p9_debug_flags { P9_DEBUG_TRANS = (1<<6), P9_DEBUG_SLABS = (1<<7), P9_DEBUG_FCALL = (1<<8), + P9_DEBUG_FID = (1<<9), }; extern unsigned int p9_debug_level; #define P9_DPRINTK(level, format, arg...) \ do { \ - if ((p9_debug_level & level) == level) \ + if (level == P9_DEBUG_9P) \ + printk(KERN_NOTICE "(%8.8d) " \ + format , task_pid_nr(current) , ## arg); \ + else if ((p9_debug_level & level) == level) \ printk(KERN_NOTICE "-- %s (%d): " \ format , __func__, task_pid_nr(current) , ## arg); \ } while (0) diff --git a/include/net/9p/client.h b/include/net/9p/client.h index 475ef5cf1644..1e49b4d1030b 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -77,6 +77,7 @@ enum p9_req_status_t { * struct p9_req_t - request slots * @status: status of this request slot * @t_err: transport error + * @flush_tag: tag of request being flushed (for flush requests) * @wq: wait_queue for the client to block on for this request * @tc: the request fcall structure * @rc: the response fcall structure @@ -97,10 +98,10 @@ enum p9_req_status_t { struct p9_req_t { int status; int t_err; + u16 flush_tag; wait_queue_head_t *wq; struct p9_fcall *tc; struct p9_fcall *rc; - u16 flush_tag; void *aux; struct list_head req_list; @@ -199,10 +200,12 @@ int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, u32 count); int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, u64 offset, u32 count); -struct p9_stat *p9_client_stat(struct p9_fid *fid); +struct p9_wstat *p9_client_stat(struct p9_fid *fid); int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst); struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); void p9_client_cb(struct p9_client *c, struct p9_req_t *req); +void p9stat_free(struct p9_wstat *); + #endif /* NET_9P_CLIENT_H */ diff --git a/net/9p/client.c b/net/9p/client.c index 6004fded6682..2a166bfb95a3 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -35,6 +35,7 @@ #include #include #include +#include "protocol.h" /* * Client Option Parsing (code inspired by NFS code) @@ -55,8 +56,8 @@ static const match_table_t tokens = { {Opt_err, NULL}, }; -static int -p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc); +static struct p9_req_t * +p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); /** * v9fs_parse_options - parse mount options into session structure @@ -138,10 +139,11 @@ static int parse_opts(char *opts, struct p9_client *clnt) * */ -struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) +static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) { unsigned long flags; int row, col; + struct p9_req_t *req; /* This looks up the original request by tag so we know which * buffer to read the data into */ @@ -157,19 +159,11 @@ struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) if (!c->reqs[row]) { printk(KERN_ERR "Couldn't grow tag array\n"); - BUG(); + return ERR_PTR(-ENOMEM); } for (col = 0; col < P9_ROW_MAXTAG; col++) { c->reqs[row][col].status = REQ_STATUS_IDLE; - c->reqs[row][col].flush_tag = P9_NOTAG; - c->reqs[row][col].wq = kmalloc( - sizeof(wait_queue_head_t), GFP_ATOMIC); - if (!c->reqs[row][col].wq) { - printk(KERN_ERR - "Couldn't grow tag array\n"); - BUG(); - } - init_waitqueue_head(c->reqs[row][col].wq); + c->reqs[row][col].tc = NULL; } c->max_tag += P9_ROW_MAXTAG; } @@ -178,12 +172,39 @@ struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) row = tag / P9_ROW_MAXTAG; col = tag % P9_ROW_MAXTAG; - c->reqs[row][col].status = REQ_STATUS_ALLOC; - c->reqs[row][col].flush_tag = P9_NOTAG; + req = &c->reqs[row][col]; + if (!req->tc) { + req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); + if (!req->wq) { + printk(KERN_ERR "Couldn't grow tag array\n"); + return ERR_PTR(-ENOMEM); + } + init_waitqueue_head(req->wq); + req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, + GFP_KERNEL); + req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, + GFP_KERNEL); + if ((!req->tc) || (!req->rc)) { + printk(KERN_ERR "Couldn't grow tag array\n"); + kfree(req->tc); + kfree(req->rc); + return ERR_PTR(-ENOMEM); + } + req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall); + req->tc->capacity = c->msize; + req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall); + req->rc->capacity = c->msize; + } + + p9pdu_reset(req->tc); + p9pdu_reset(req->rc); + + req->flush_tag = 0; + req->tc->tag = tag-1; + req->status = REQ_STATUS_ALLOC; return &c->reqs[row][col]; } -EXPORT_SYMBOL(p9_tag_alloc); /** * p9_tag_lookup - lookup a request by tag @@ -264,43 +285,16 @@ static void p9_tag_cleanup(struct p9_client *c) /* free requests associated with tags */ for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { - for (col = 0; col < P9_ROW_MAXTAG; col++) + for (col = 0; col < P9_ROW_MAXTAG; col++) { kfree(c->reqs[row][col].wq); + kfree(c->reqs[row][col].tc); + kfree(c->reqs[row][col].rc); + } kfree(c->reqs[row]); } c->max_tag = 0; } -/** - * p9_client_flush - flush (cancel) a request - * c: client state - * req: request to cancel - * - * This sents a flush for a particular requests and links - * the flush request to the original request. The current - * code only supports a single flush request although the protocol - * allows for multiple flush requests to be sent for a single request. - * - */ - -static int p9_client_flush(struct p9_client *c, struct p9_req_t *req) -{ - struct p9_fcall *tc, *rc = NULL; - int err; - - P9_DPRINTK(P9_DEBUG_9P, "client %p tag %d\n", c, req->tc->tag); - - tc = p9_create_tflush(req->tc->tag); - if (IS_ERR(tc)) - return PTR_ERR(tc); - - err = p9_client_rpc(c, tc, &rc); - - /* we don't free anything here because RPC isn't complete */ - - return err; -} - /** * p9_free_req - free a request and clean-up as necessary * c: client state @@ -308,15 +302,17 @@ static int p9_client_flush(struct p9_client *c, struct p9_req_t *req) * */ -void p9_free_req(struct p9_client *c, struct p9_req_t *r) +static void p9_free_req(struct p9_client *c, struct p9_req_t *r) { - r->flush_tag = P9_NOTAG; + int tag = r->tc->tag; + P9_DPRINTK(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag); + r->status = REQ_STATUS_IDLE; - if (r->tc->tag != P9_NOTAG && p9_idpool_check(r->tc->tag, c->tagpool)) - p9_idpool_put(r->tc->tag, c->tagpool); + if (tag != P9_NOTAG && p9_idpool_check(tag, c->tagpool)) + p9_idpool_put(tag, c->tagpool); /* if this was a flush request we have to free response fcall */ - if (r->tc->id == P9_TFLUSH) { + if (r->rc->id == P9_RFLUSH) { kfree(r->tc); kfree(r->rc); } @@ -333,30 +329,28 @@ void p9_client_cb(struct p9_client *c, struct p9_req_t *req) struct p9_req_t *other_req; unsigned long flags; - P9_DPRINTK(P9_DEBUG_MUX, ": %d\n", req->tc->tag); + P9_DPRINTK(P9_DEBUG_MUX, " tag %d\n", req->tc->tag); if (req->status == REQ_STATUS_ERROR) wake_up(req->wq); - if (req->tc->id == P9_TFLUSH) { /* flush receive path */ - P9_DPRINTK(P9_DEBUG_MUX, "flush: %d\n", req->tc->tag); + if (req->flush_tag) { /* flush receive path */ + P9_DPRINTK(P9_DEBUG_9P, "<<< RFLUSH %d\n", req->tc->tag); spin_lock_irqsave(&c->lock, flags); - other_req = p9_tag_lookup(c, req->tc->params.tflush.oldtag); - if (other_req->flush_tag != req->tc->tag) /* stale flush */ + other_req = p9_tag_lookup(c, req->flush_tag); + if (other_req->status != REQ_STATUS_FLSH) /* stale flush */ spin_unlock_irqrestore(&c->lock, flags); else { - BUG_ON(other_req->status != REQ_STATUS_FLSH); other_req->status = REQ_STATUS_FLSHD; spin_unlock_irqrestore(&c->lock, flags); wake_up(other_req->wq); } p9_free_req(c, req); } else { /* normal receive path */ - P9_DPRINTK(P9_DEBUG_MUX, "normal: %d\n", req->tc->tag); + P9_DPRINTK(P9_DEBUG_MUX, "normal: tag %d\n", req->tc->tag); spin_lock_irqsave(&c->lock, flags); if (req->status != REQ_STATUS_FLSHD) req->status = REQ_STATUS_RCVD; - req->flush_tag = P9_NOTAG; spin_unlock_irqrestore(&c->lock, flags); wake_up(req->wq); P9_DPRINTK(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag); @@ -364,29 +358,165 @@ void p9_client_cb(struct p9_client *c, struct p9_req_t *req) } EXPORT_SYMBOL(p9_client_cb); +/** + * p9_parse_header - parse header arguments out of a packet + * @pdu: packet to parse + * @size: size of packet + * @type: type of request + * @tag: tag of packet + * @rewind: set if we need to rewind offset afterwards + */ + +int +p9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type, int16_t *tag, + int rewind) +{ + int8_t r_type; + int16_t r_tag; + int32_t r_size; + int offset = pdu->offset; + int err; + + pdu->offset = 0; + if (pdu->size == 0) + pdu->size = 7; + + err = p9pdu_readf(pdu, 0, "dbw", &r_size, &r_type, &r_tag); + if (err) + goto rewind_and_exit; + + pdu->size = r_size; + pdu->id = r_type; + pdu->tag = r_tag; + + P9_DPRINTK(P9_DEBUG_MUX, "pdu: type: %d tag: %d size=%d offset=%d\n", + pdu->id, pdu->tag, pdu->size, pdu->offset); + + if (type) + *type = r_type; + if (tag) + *tag = r_tag; + if (size) + *size = r_size; + + +rewind_and_exit: + if (rewind) + pdu->offset = offset; + return err; +} +EXPORT_SYMBOL(p9_parse_header); + +/** + * p9_check_errors - check 9p packet for error return and process it + * @c: current client instance + * @req: request to parse and check for error conditions + * + * returns error code if one is discovered, otherwise returns 0 + * + * this will have to be more complicated if we have multiple + * error packet types + */ + +static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) +{ + int8_t type; + int err; + + err = p9_parse_header(req->rc, NULL, &type, NULL, 0); + if (err) { + P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err); + return err; + } + + if (type == P9_RERROR) { + int ecode; + char *ename; + + err = p9pdu_readf(req->rc, c->dotu, "s?d", &ename, &ecode); + if (err) { + P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", + err); + return err; + } + + if (c->dotu) + err = -ecode; + + if (!err) { + err = p9_errstr2errno(ename, strlen(ename)); + + /* string match failed */ + if (!err) + err = -ESERVERFAULT; + } + + P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); + + kfree(ename); + } else + err = 0; + + return err; +} + +/** + * p9_client_flush - flush (cancel) a request + * c: client state + * req: request to cancel + * + * This sents a flush for a particular requests and links + * the flush request to the original request. The current + * code only supports a single flush request although the protocol + * allows for multiple flush requests to be sent for a single request. + * + */ + +static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq) +{ + struct p9_req_t *req; + int16_t oldtag; + int err; + + err = p9_parse_header(oldreq->tc, NULL, NULL, &oldtag, 1); + if (err) + return err; + + P9_DPRINTK(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag); + + req = p9_client_rpc(c, P9_TFLUSH, "w", oldtag); + if (IS_ERR(req)) + return PTR_ERR(req); + + req->flush_tag = oldtag; + + /* we don't free anything here because RPC isn't complete */ + return 0; +} + /** * p9_client_rpc - issue a request and wait for a response * @c: client session - * @tc: &p9_fcall request to transmit - * @rc: &p9_fcall to put reponse into + * @type: type of request + * @fmt: protocol format string (see protocol.c) * - * Returns 0 on success, error code on failure + * Returns request structure (which client must free using p9_free_req) */ -static int -p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) +static struct p9_req_t * +p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) { - int tag, err, size; - char *rdata; + va_list ap; + int tag, err; struct p9_req_t *req; unsigned long flags; int sigpending; int flushed = 0; - P9_DPRINTK(P9_DEBUG_9P, "client %p tc %p rc %p\n", c, tc, rc); + P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type); if (c->status != Connected) - return -EIO; + return ERR_PTR(-EIO); if (signal_pending(current)) { sigpending = 1; @@ -395,50 +525,22 @@ p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) sigpending = 0; tag = P9_NOTAG; - if (tc->id != P9_TVERSION) { + if (type != P9_TVERSION) { tag = p9_idpool_get(c->tagpool); if (tag < 0) - return -ENOMEM; + return ERR_PTR(-ENOMEM); } req = p9_tag_alloc(c, tag); + if (IS_ERR(req)) + return req; - /* if this is a flush request, backlink flush request now to - * avoid race conditions later. */ - if (tc->id == P9_TFLUSH) { - struct p9_req_t *other_req = - p9_tag_lookup(c, tc->params.tflush.oldtag); - if (other_req->status == REQ_STATUS_FLSH) - other_req->flush_tag = tag; - } - - p9_set_tag(tc, tag); - - /* - * if client passed in a pre-allocated response fcall struct - * then we just use that, otherwise we allocate one. - */ - - if (rc == NULL) - req->rc = NULL; - else - req->rc = *rc; - if (req->rc == NULL) { - req->rc = kmalloc(sizeof(struct p9_fcall) + c->msize, - GFP_KERNEL); - if (!req->rc) { - err = -ENOMEM; - p9_idpool_put(tag, c->tagpool); - p9_free_req(c, req); - goto reterr; - } - *rc = req->rc; - } - - rdata = (char *)req->rc+sizeof(struct p9_fcall); - - req->tc = tc; - P9_DPRINTK(P9_DEBUG_9P, "request: tc: %p rc: %p\n", req->tc, req->rc); + /* marshall the data */ + p9pdu_prepare(req->tc, tag, type); + va_start(ap, fmt); + err = p9pdu_vwritef(req->tc, c->dotu, fmt, ap); + va_end(ap); + p9pdu_finalize(req->tc); err = c->trans_mod->request(c, req); if (err < 0) { @@ -447,28 +549,28 @@ p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) } /* if it was a flush we just transmitted, return our tag */ - if (tc->id == P9_TFLUSH) - return 0; + if (type == P9_TFLUSH) + return req; again: - P9_DPRINTK(P9_DEBUG_9P, "wait %p tag: %d\n", req->wq, tag); + P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d\n", req->wq, tag); err = wait_event_interruptible(*req->wq, req->status >= REQ_STATUS_RCVD); - P9_DPRINTK(P9_DEBUG_9P, "wait %p tag: %d returned %d (flushed=%d)\n", + P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d returned %d (flushed=%d)\n", req->wq, tag, err, flushed); if (req->status == REQ_STATUS_ERROR) { - P9_DPRINTK(P9_DEBUG_9P, "req_status error %d\n", req->t_err); + P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); err = req->t_err; } else if (err == -ERESTARTSYS && flushed) { - P9_DPRINTK(P9_DEBUG_9P, "flushed - going again\n"); + P9_DPRINTK(P9_DEBUG_MUX, "flushed - going again\n"); goto again; } else if (req->status == REQ_STATUS_FLSHD) { - P9_DPRINTK(P9_DEBUG_9P, "flushed - erestartsys\n"); + P9_DPRINTK(P9_DEBUG_MUX, "flushed - erestartsys\n"); err = -ERESTARTSYS; } if ((err == -ERESTARTSYS) && (c->status == Connected) && (!flushed)) { - P9_DPRINTK(P9_DEBUG_9P, "flushing\n"); + P9_DPRINTK(P9_DEBUG_MUX, "flushing\n"); spin_lock_irqsave(&c->lock, flags); if (req->status == REQ_STATUS_SENT) req->status = REQ_STATUS_FLSH; @@ -493,42 +595,17 @@ again: if (err < 0) goto reterr; - size = le32_to_cpu(*(__le32 *) rdata); - - err = p9_deserialize_fcall(rdata, size, req->rc, c->dotu); - if (err < 0) { - P9_DPRINTK(P9_DEBUG_9P, - "9p debug: client rpc deserialize returned %d\n", err); - goto reterr; + err = p9_check_errors(c, req); + if (!err) { + P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d\n", c, type); + return req; } - if (req->rc->id == P9_RERROR) { - int ecode = req->rc->params.rerror.errno; - struct p9_str *ename = &req->rc->params.rerror.error; - - P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len, - ename->str); - - if (c->dotu) - err = -ecode; - - if (!err) { - err = p9_errstr2errno(ename->str, ename->len); - - /* string match failed */ - if (!err) { - PRINT_FCALL_ERROR("unknown error", req->rc); - err = -ESERVERFAULT; - } - } - } else - err = 0; - reterr: + P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d error: %d\n", c, type, + err); p9_free_req(c, req); - - P9_DPRINTK(P9_DEBUG_9P, "returning %d\n", err); - return err; + return ERR_PTR(err); } static struct p9_fid *p9_fid_create(struct p9_client *clnt) @@ -536,7 +613,7 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt) int err; struct p9_fid *fid; - P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); + P9_DPRINTK(P9_DEBUG_FID, "clnt %p\n", clnt); fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL); if (!fid) return ERR_PTR(-ENOMEM); @@ -569,7 +646,7 @@ static void p9_fid_destroy(struct p9_fid *fid) { struct p9_client *clnt; - P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); + P9_DPRINTK(P9_DEBUG_FID, "fid %d\n", fid->fid); clnt = fid->clnt; p9_idpool_put(fid->fid, clnt->fidpool); spin_lock(&clnt->lock); @@ -578,49 +655,46 @@ static void p9_fid_destroy(struct p9_fid *fid) kfree(fid); } -static int p9_client_version(struct p9_client *clnt) +int p9_client_version(struct p9_client *c) { int err = 0; - struct p9_fcall *tc, *rc; - struct p9_str *version; + struct p9_req_t *req; + char *version; + int msize; - P9_DPRINTK(P9_DEBUG_9P, "%p\n", clnt); - err = 0; - tc = NULL; - rc = NULL; - - tc = p9_create_tversion(clnt->msize, - clnt->dotu ? "9P2000.u" : "9P2000"); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto error; - } + P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d extended %d\n", + c->msize, c->dotu); + req = p9_client_rpc(c, P9_TVERSION, "ds", c->msize, + c->dotu ? "9P2000.u" : "9P2000"); + if (IS_ERR(req)) + return PTR_ERR(req); - err = p9_client_rpc(clnt, tc, &rc); - if (err) + err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version); + if (err) { + P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); goto error; + } - version = &rc->params.rversion.version; - if (version->len == 8 && !memcmp(version->str, "9P2000.u", 8)) - clnt->dotu = 1; - else if (version->len == 6 && !memcmp(version->str, "9P2000", 6)) - clnt->dotu = 0; + P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version); + if (!memcmp(version, "9P2000.u", 8)) + c->dotu = 1; + else if (!memcmp(version, "9P2000", 6)) + c->dotu = 0; else { err = -EREMOTEIO; goto error; } - if (rc->params.rversion.msize < clnt->msize) - clnt->msize = rc->params.rversion.msize; + if (msize < c->msize) + c->msize = msize; error: - kfree(tc); - kfree(rc); + kfree(version); + p9_free_req(c, req); return err; } -EXPORT_SYMBOL(p9_client_auth); +EXPORT_SYMBOL(p9_client_version); struct p9_client *p9_client_create(const char *dev_name, char *options) { @@ -656,7 +730,7 @@ struct p9_client *p9_client_create(const char *dev_name, char *options) goto error; } - P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n", + P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d dotu %d\n", clnt, clnt->trans_mod, clnt->msize, clnt->dotu); err = clnt->trans_mod->create(clnt, dev_name, options); @@ -682,7 +756,7 @@ void p9_client_destroy(struct p9_client *clnt) { struct p9_fid *fid, *fidptr; - P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); + P9_DPRINTK(P9_DEBUG_MUX, "clnt %p\n", clnt); if (clnt->trans_mod) clnt->trans_mod->close(clnt); @@ -712,14 +786,13 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, char *uname, u32 n_uname, char *aname) { int err; - struct p9_fcall *tc, *rc; + struct p9_req_t *req; struct p9_fid *fid; + struct p9_qid qid; - P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n", - clnt, afid?afid->fid:-1, uname, aname); + P9_DPRINTK(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n", + afid ? afid->fid : -1, uname, aname); err = 0; - tc = NULL; - rc = NULL; fid = p9_fid_create(clnt); if (IS_ERR(fid)) { @@ -728,73 +801,75 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, goto error; } - tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname, - n_uname, clnt->dotu); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; + req = p9_client_rpc(clnt, P9_TATTACH, "ddss?d", fid->fid, + afid ? afid->fid : P9_NOFID, uname, aname, n_uname); + if (IS_ERR(req)) { + err = PTR_ERR(req); goto error; } - err = p9_client_rpc(clnt, tc, &rc); - if (err) + err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); + if (err) { + p9_free_req(clnt, req); goto error; + } - memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid)); - kfree(tc); - kfree(rc); + P9_DPRINTK(P9_DEBUG_9P, "<<< RATTACH qid %x.%llx.%x\n", + qid.type, qid.path, qid.version); + + memmove(&fid->qid, &qid, sizeof(struct p9_qid)); + + p9_free_req(clnt, req); return fid; error: - kfree(tc); - kfree(rc); if (fid) p9_fid_destroy(fid); return ERR_PTR(err); } EXPORT_SYMBOL(p9_client_attach); -struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, - u32 n_uname, char *aname) +struct p9_fid * +p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname) { int err; - struct p9_fcall *tc, *rc; - struct p9_fid *fid; + struct p9_req_t *req; + struct p9_qid qid; + struct p9_fid *afid; - P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname, - aname); + P9_DPRINTK(P9_DEBUG_9P, ">>> TAUTH uname %s aname %s\n", uname, aname); err = 0; - tc = NULL; - rc = NULL; - fid = p9_fid_create(clnt); - if (IS_ERR(fid)) { - err = PTR_ERR(fid); - fid = NULL; + afid = p9_fid_create(clnt); + if (IS_ERR(afid)) { + err = PTR_ERR(afid); + afid = NULL; goto error; } - tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; + req = p9_client_rpc(clnt, P9_TAUTH, "dss?d", + afid ? afid->fid : P9_NOFID, uname, aname, n_uname); + if (IS_ERR(req)) { + err = PTR_ERR(req); goto error; } - err = p9_client_rpc(clnt, tc, &rc); - if (err) + err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); + if (err) { + p9_free_req(clnt, req); goto error; + } - memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid)); - kfree(tc); - kfree(rc); - return fid; + P9_DPRINTK(P9_DEBUG_9P, "<<< RAUTH qid %x.%llx.%x\n", + qid.type, qid.path, qid.version); + + memmove(&afid->qid, &qid, sizeof(struct p9_qid)); + p9_free_req(clnt, req); + return afid; error: - kfree(tc); - kfree(rc); - if (fid) - p9_fid_destroy(fid); + if (afid) + p9_fid_destroy(afid); return ERR_PTR(err); } EXPORT_SYMBOL(p9_client_auth); @@ -803,15 +878,13 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, int clone) { int err; - struct p9_fcall *tc, *rc; struct p9_client *clnt; struct p9_fid *fid; + struct p9_qid *wqids; + struct p9_req_t *req; + int16_t nwqids, count; - P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n", - oldfid->fid, nwname, wnames?wnames[0]:NULL); err = 0; - tc = NULL; - rc = NULL; clnt = oldfid->clnt; if (clone) { fid = p9_fid_create(clnt); @@ -825,53 +898,46 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, } else fid = oldfid; - tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; + + P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n", + oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL); + + req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid, + nwname, wnames); + if (IS_ERR(req)) { + err = PTR_ERR(req); goto error; } - err = p9_client_rpc(clnt, tc, &rc); - if (err) { - if (rc && rc->id == P9_RWALK) - goto clunk_fid; - else - goto error; - } + err = p9pdu_readf(req->rc, clnt->dotu, "R", &nwqids, &wqids); + p9_free_req(clnt, req); + if (err) + goto clunk_fid; - if (rc->params.rwalk.nwqid != nwname) { + P9_DPRINTK(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids); + + if (nwqids != nwname) { err = -ENOENT; goto clunk_fid; } + for (count = 0; count < nwqids; count++) + P9_DPRINTK(P9_DEBUG_9P, "<<< [%d] %x.%llx.%x\n", + count, wqids[count].type, wqids[count].path, + wqids[count].version); + if (nwname) - memmove(&fid->qid, - &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1], - sizeof(struct p9_qid)); + memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid)); else fid->qid = oldfid->qid; - kfree(tc); - kfree(rc); return fid; clunk_fid: - kfree(tc); - kfree(rc); - rc = NULL; - tc = p9_create_tclunk(fid->fid); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto error; - } - - p9_client_rpc(clnt, tc, &rc); + p9_client_clunk(fid); + fid = NULL; error: - kfree(tc); - kfree(rc); if (fid && (fid != oldfid)) p9_fid_destroy(fid); @@ -882,35 +948,36 @@ EXPORT_SYMBOL(p9_client_walk); int p9_client_open(struct p9_fid *fid, int mode) { int err; - struct p9_fcall *tc, *rc; struct p9_client *clnt; + struct p9_req_t *req; + struct p9_qid qid; + int iounit; - P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode); + P9_DPRINTK(P9_DEBUG_9P, ">>> TOPEN fid %d mode %d\n", fid->fid, mode); err = 0; - tc = NULL; - rc = NULL; clnt = fid->clnt; if (fid->mode != -1) return -EINVAL; - tc = p9_create_topen(fid->fid, mode); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto done; + req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; } - err = p9_client_rpc(clnt, tc, &rc); + err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); + p9_free_req(clnt, req); if (err) - goto done; + goto error; + + P9_DPRINTK(P9_DEBUG_9P, "<<< ROPEN qid %x.%llx.%x iounit %x\n", + qid.type, qid.path, qid.version, iounit); fid->mode = mode; - fid->iounit = rc->params.ropen.iounit; + fid->iounit = iounit; -done: - kfree(tc); - kfree(rc); +error: return err; } EXPORT_SYMBOL(p9_client_open); @@ -919,37 +986,38 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, char *extension) { int err; - struct p9_fcall *tc, *rc; struct p9_client *clnt; + struct p9_req_t *req; + struct p9_qid qid; + int iounit; - P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid, - name, perm, mode); + P9_DPRINTK(P9_DEBUG_9P, ">>> TCREATE fid %d name %s perm %d mode %d\n", + fid->fid, name, perm, mode); err = 0; - tc = NULL; - rc = NULL; clnt = fid->clnt; if (fid->mode != -1) return -EINVAL; - tc = p9_create_tcreate(fid->fid, name, perm, mode, extension, - clnt->dotu); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto done; + req = p9_client_rpc(clnt, P9_TCREATE, "dsdb?s", fid->fid, name, perm, + mode, extension); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; } - err = p9_client_rpc(clnt, tc, &rc); + err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); + p9_free_req(clnt, req); if (err) - goto done; + goto error; + + P9_DPRINTK(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n", + qid.type, qid.path, qid.version, iounit); fid->mode = mode; - fid->iounit = rc->params.ropen.iounit; + fid->iounit = iounit; -done: - kfree(tc); - kfree(rc); +error: return err; } EXPORT_SYMBOL(p9_client_fcreate); @@ -957,31 +1025,25 @@ EXPORT_SYMBOL(p9_client_fcreate); int p9_client_clunk(struct p9_fid *fid) { int err; - struct p9_fcall *tc, *rc; struct p9_client *clnt; + struct p9_req_t *req; - P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); + P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid); err = 0; - tc = NULL; - rc = NULL; clnt = fid->clnt; - tc = p9_create_tclunk(fid->fid); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto done; + req = p9_client_rpc(clnt, P9_TCLUNK, "d", fid->fid); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; } - err = p9_client_rpc(clnt, tc, &rc); - if (err) - goto done; + P9_DPRINTK(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid); + p9_free_req(clnt, req); p9_fid_destroy(fid); -done: - kfree(tc); - kfree(rc); +error: return err; } EXPORT_SYMBOL(p9_client_clunk); @@ -989,31 +1051,25 @@ EXPORT_SYMBOL(p9_client_clunk); int p9_client_remove(struct p9_fid *fid) { int err; - struct p9_fcall *tc, *rc; struct p9_client *clnt; + struct p9_req_t *req; - P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); + P9_DPRINTK(P9_DEBUG_9P, ">>> TREMOVE fid %d\n", fid->fid); err = 0; - tc = NULL; - rc = NULL; clnt = fid->clnt; - tc = p9_create_tremove(fid->fid); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto done; + req = p9_client_rpc(clnt, P9_TREMOVE, "d", fid->fid); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; } - err = p9_client_rpc(clnt, tc, &rc); - if (err) - goto done; + P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid); + p9_free_req(clnt, req); p9_fid_destroy(fid); -done: - kfree(tc); - kfree(rc); +error: return err; } EXPORT_SYMBOL(p9_client_remove); @@ -1022,15 +1078,14 @@ int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, u32 count) { - int err, n, rsize, total; - struct p9_fcall *tc, *rc; + int err, rsize, total; struct p9_client *clnt; + struct p9_req_t *req; + char *dataptr; - P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid, + P9_DPRINTK(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", fid->fid, (long long unsigned) offset, count); err = 0; - tc = NULL; - rc = NULL; clnt = fid->clnt; total = 0; @@ -1038,53 +1093,40 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) rsize = clnt->msize - P9_IOHDRSZ; - do { - if (count < rsize) - rsize = count; + if (count < rsize) + rsize = count; - tc = p9_create_tread(fid->fid, offset, rsize); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto error; - } + req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; + } - err = p9_client_rpc(clnt, tc, &rc); - if (err) - goto error; + err = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr); + if (err) + goto free_and_error; - n = rc->params.rread.count; - if (n > count) - n = count; + P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); - if (data) { - memmove(data, rc->params.rread.data, n); - data += n; - } + if (data) { + memmove(data, dataptr, count); + data += count; + } - if (udata) { - err = copy_to_user(udata, rc->params.rread.data, n); - if (err) { - err = -EFAULT; - goto error; - } - udata += n; + if (udata) { + err = copy_to_user(udata, dataptr, count); + if (err) { + err = -EFAULT; + goto free_and_error; } + } - count -= n; - offset += n; - total += n; - kfree(tc); - tc = NULL; - kfree(rc); - rc = NULL; - } while (count > 0 && n == rsize); - - return total; + p9_free_req(clnt, req); + return count; +free_and_error: + p9_free_req(clnt, req); error: - kfree(tc); - kfree(rc); return err; } EXPORT_SYMBOL(p9_client_read); @@ -1093,15 +1135,13 @@ int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, u64 offset, u32 count) { - int err, n, rsize, total; - struct p9_fcall *tc, *rc; + int err, rsize, total; struct p9_client *clnt; + struct p9_req_t *req; - P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, - (long long unsigned) offset, count); + P9_DPRINTK(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n", + fid->fid, (long long unsigned) offset, count); err = 0; - tc = NULL; - rc = NULL; clnt = fid->clnt; total = 0; @@ -1109,129 +1149,70 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) rsize = clnt->msize - P9_IOHDRSZ; - do { - if (count < rsize) - rsize = count; - - if (data) - tc = p9_create_twrite(fid->fid, offset, rsize, data); - else - tc = p9_create_twrite_u(fid->fid, offset, rsize, udata); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto error; - } - - err = p9_client_rpc(clnt, tc, &rc); - if (err) - goto error; - - n = rc->params.rread.count; - count -= n; - - if (data) - data += n; - else - udata += n; + if (count < rsize) + rsize = count; + if (data) + req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset, + rsize, data); + else + req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset, + rsize, udata); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; + } - offset += n; - total += n; - kfree(tc); - tc = NULL; - kfree(rc); - rc = NULL; - } while (count > 0); + err = p9pdu_readf(req->rc, clnt->dotu, "d", &count); + if (err) + goto free_and_error; + P9_DPRINTK(P9_DEBUG_9P, "<<< RWRITE count %d\n", count); - return total; + p9_free_req(clnt, req); + return count; +free_and_error: + p9_free_req(clnt, req); error: - kfree(tc); - kfree(rc); return err; } EXPORT_SYMBOL(p9_client_write); -static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu) +struct p9_wstat *p9_client_stat(struct p9_fid *fid) { - int n; - char *p; - struct p9_stat *ret; - - n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len + - st->muid.len; + int err; + struct p9_client *clnt; + struct p9_wstat *ret = kmalloc(sizeof(struct p9_wstat), GFP_KERNEL); + struct p9_req_t *req; + u16 ignored; - if (dotu) - n += st->extension.len; + P9_DPRINTK(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid); - ret = kmalloc(n, GFP_KERNEL); if (!ret) return ERR_PTR(-ENOMEM); - memmove(ret, st, sizeof(struct p9_stat)); - p = ((char *) ret) + sizeof(struct p9_stat); - memmove(p, st->name.str, st->name.len); - ret->name.str = p; - p += st->name.len; - memmove(p, st->uid.str, st->uid.len); - ret->uid.str = p; - p += st->uid.len; - memmove(p, st->gid.str, st->gid.len); - ret->gid.str = p; - p += st->gid.len; - memmove(p, st->muid.str, st->muid.len); - ret->muid.str = p; - p += st->muid.len; - - if (dotu) { - memmove(p, st->extension.str, st->extension.len); - ret->extension.str = p; - p += st->extension.len; - } - - return ret; -} - -struct p9_stat *p9_client_stat(struct p9_fid *fid) -{ - int err; - struct p9_fcall *tc, *rc; - struct p9_client *clnt; - struct p9_stat *ret; - - P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); err = 0; - tc = NULL; - rc = NULL; - ret = NULL; clnt = fid->clnt; - tc = p9_create_tstat(fid->fid); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; + req = p9_client_rpc(clnt, P9_TSTAT, "d", fid->fid); + if (IS_ERR(req)) { + err = PTR_ERR(req); goto error; } - err = p9_client_rpc(clnt, tc, &rc); + err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret); + p9_free_req(clnt, req); if (err) goto error; - ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu); - if (IS_ERR(ret)) { - err = PTR_ERR(ret); - ret = NULL; - goto error; - } + P9_DPRINTK(P9_DEBUG_9P, + "<<< RSTAT sz=%x type=%x dev=%x qid=%2.2x %4.4x %8.8llx" + " mode=%8.8x uid=%d gid=%d size=%lld %s\n", + ret->size, ret->type, ret->dev, ret->qid.type, + ret->qid.version, ret->qid.path, ret->mode, + ret->n_uid, ret->n_gid, ret->length, ret->name); - kfree(tc); - kfree(rc); return ret; - error: - kfree(tc); - kfree(rc); - kfree(ret); return ERR_PTR(err); } EXPORT_SYMBOL(p9_client_stat); @@ -1239,27 +1220,23 @@ EXPORT_SYMBOL(p9_client_stat); int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst) { int err; - struct p9_fcall *tc, *rc; + struct p9_req_t *req; struct p9_client *clnt; - P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); + P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid); err = 0; - tc = NULL; - rc = NULL; clnt = fid->clnt; - tc = p9_create_twstat(fid->fid, wst, clnt->dotu); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto done; + req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, 0, wst); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; } - err = p9_client_rpc(clnt, tc, &rc); + P9_DPRINTK(P9_DEBUG_9P, "<<< RWSTAT fid %d\n", fid->fid); -done: - kfree(tc); - kfree(rc); + p9_free_req(clnt, req); +error: return err; } EXPORT_SYMBOL(p9_client_wstat); diff --git a/net/9p/protocol.c b/net/9p/protocol.c index 43e98220e9a4..4ebeffd21d3d 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include "protocol.h" @@ -51,6 +52,38 @@ static int p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...); +#define PACKET_DEBUG 0 + +void +p9pdu_dump(int way, struct p9_fcall *pdu) +{ + int i, n; + u8 *data = pdu->sdata; + int datalen = pdu->size; + char buf[255]; + int buflen = 255; + + i = n = 0; + if (datalen > (buflen-16)) + datalen = buflen-16; + while (i < datalen) { + n += scnprintf(buf + n, buflen - n, "%02x ", data[i]); + if (i%4 == 3) + n += scnprintf(buf + n, buflen - n, " "); + if (i%32 == 31) + n += scnprintf(buf + n, buflen - n, "\n"); + + i++; + } + n += scnprintf(buf + n, buflen - n, "\n"); + + if (way) + printk(KERN_NOTICE "[[(%d)[ %s\n", datalen, buf); + else + printk(KERN_NOTICE "]](%d)] %s\n", datalen, buf); +} +EXPORT_SYMBOL(p9pdu_dump); + void p9stat_free(struct p9_wstat *stbuf) { kfree(stbuf->name); @@ -77,6 +110,18 @@ static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size) return size - len; } +static size_t +pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) +{ + size_t len = MIN(pdu->capacity - pdu->size, size); + int err = copy_from_user(&pdu->sdata[pdu->size], udata, len); + if (err) + printk(KERN_WARNING "pdu_write_u returning: %d\n", err); + + pdu->size += len; + return size - len; +} + /* b - int8_t w - int16_t @@ -174,7 +219,6 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) stbuf->extension = NULL; stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = -1; - errcode = p9pdu_readf(pdu, optional, "wwdQdddqssss?sddd", @@ -332,7 +376,6 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) case 's':{ const char *ptr = va_arg(ap, const char *); int16_t len = 0; - if (ptr) len = MIN(strlen(ptr), USHORT_MAX); @@ -356,7 +399,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) p9pdu_writef(pdu, optional, "wwdQdddqssss?sddd", stbuf->size, stbuf->type, - stbuf->dev, stbuf->qid, + stbuf->dev, &stbuf->qid, stbuf->mode, stbuf->atime, stbuf->mtime, stbuf->length, stbuf->name, stbuf->uid, @@ -374,6 +417,16 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) errcode = -EFAULT; } break; + case 'U':{ + int32_t count = va_arg(ap, int32_t); + const char __user *udata = + va_arg(ap, const void *); + errcode = + p9pdu_writef(pdu, optional, "d", count); + if (!errcode && pdu_write_u(pdu, udata, count)) + errcode = -EFAULT; + } + break; case 'T':{ int16_t nwname = va_arg(ap, int); const char **wnames = va_arg(ap, const char **); @@ -455,3 +508,29 @@ p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...) return ret; } + +int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type) +{ + return p9pdu_writef(pdu, 0, "dbw", 0, type, tag); +} + +int p9pdu_finalize(struct p9_fcall *pdu) +{ + int size = pdu->size; + int err; + + pdu->size = 0; + err = p9pdu_writef(pdu, 0, "d", size); + pdu->size = size; + + if (PACKET_DEBUG) + p9pdu_dump(0, pdu); + + return err; +} + +void p9pdu_reset(struct p9_fcall *pdu) +{ + pdu->offset = 0; + pdu->size = 0; +} diff --git a/net/9p/protocol.h b/net/9p/protocol.h index 596ee10d506f..ccde462e7ac5 100644 --- a/net/9p/protocol.h +++ b/net/9p/protocol.h @@ -27,5 +27,8 @@ int p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap); - int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...); +int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type); +int p9pdu_finalize(struct p9_fcall *pdu); +void p9pdu_dump(int, struct p9_fcall *); +void p9pdu_reset(struct p9_fcall *pdu); diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index e147ec539585..e8ebe2cb7e8b 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -181,7 +181,7 @@ static void p9_mux_poll_stop(struct p9_conn *m) * */ -void p9_conn_cancel(struct p9_conn *m, int err) +static void p9_conn_cancel(struct p9_conn *m, int err) { struct p9_req_t *req, *rtmp; unsigned long flags; @@ -287,7 +287,7 @@ static void p9_read_work(struct work_struct *work) if (m->err < 0) return; - P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); + P9_DPRINTK(P9_DEBUG_TRANS, "start mux %p pos %d\n", m, m->rpos); if (!m->rbuf) { m->rbuf = m->tmp_buf; @@ -296,11 +296,11 @@ static void p9_read_work(struct work_struct *work) } clear_bit(Rpending, &m->wsched); - P9_DPRINTK(P9_DEBUG_MUX, "read mux %p pos %d size: %d = %d\n", m, + P9_DPRINTK(P9_DEBUG_TRANS, "read mux %p pos %d size: %d = %d\n", m, m->rpos, m->rsize, m->rsize-m->rpos); err = p9_fd_read(m->client, m->rbuf + m->rpos, m->rsize - m->rpos); - P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p got %d bytes\n", m, err); if (err == -EAGAIN) { clear_bit(Rworksched, &m->wsched); return; @@ -313,7 +313,7 @@ static void p9_read_work(struct work_struct *work) if ((!m->req) && (m->rpos == m->rsize)) { /* header read in */ u16 tag; - P9_DPRINTK(P9_DEBUG_MUX, "got new header\n"); + P9_DPRINTK(P9_DEBUG_TRANS, "got new header\n"); n = le32_to_cpu(*(__le32 *) m->rbuf); /* read packet size */ if (n >= m->client->msize) { @@ -324,8 +324,8 @@ static void p9_read_work(struct work_struct *work) } tag = le16_to_cpu(*(__le16 *) (m->rbuf+5)); /* read tag */ - P9_DPRINTK(P9_DEBUG_MUX, "mux %p pkt: size: %d bytes tag: %d\n", - m, n, tag); + P9_DPRINTK(P9_DEBUG_TRANS, + "mux %p pkt: size: %d bytes tag: %d\n", m, n, tag); m->req = p9_tag_lookup(m->client, tag); if (!m->req) { @@ -351,7 +351,7 @@ static void p9_read_work(struct work_struct *work) /* not an else because some packets (like clunk) have no payload */ if ((m->req) && (m->rpos == m->rsize)) { /* packet is read in */ - P9_DPRINTK(P9_DEBUG_MUX, "got new packet\n"); + P9_DPRINTK(P9_DEBUG_TRANS, "got new packet\n"); list_del(&m->req->req_list); p9_client_cb(m->client, m->req); @@ -369,7 +369,7 @@ static void p9_read_work(struct work_struct *work) n = p9_fd_poll(m->client, NULL); if (n & POLLIN) { - P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "sched read work %p\n", m); queue_work(p9_mux_wq, &m->rq); } else clear_bit(Rworksched, &m->wsched); @@ -453,11 +453,11 @@ static void p9_write_work(struct work_struct *work) spin_unlock(&m->client->lock); } - P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos, + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p pos %d size %d\n", m, m->wpos, m->wsize); clear_bit(Wpending, &m->wsched); err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos); - P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p sent %d bytes\n", m, err); if (err == -EAGAIN) { clear_bit(Wworksched, &m->wsched); return; @@ -481,7 +481,7 @@ static void p9_write_work(struct work_struct *work) n = p9_fd_poll(m->client, NULL); if (n & POLLOUT) { - P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m); queue_work(p9_mux_wq, &m->wq); } else clear_bit(Wworksched, &m->wsched); @@ -558,7 +558,8 @@ static struct p9_conn *p9_conn_create(struct p9_client *client) int n; struct p9_conn *m; - P9_DPRINTK(P9_DEBUG_MUX, "client %p msize %d\n", client, client->msize); + P9_DPRINTK(P9_DEBUG_TRANS, "client %p msize %d\n", client, + client->msize); m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL); if (!m) return ERR_PTR(-ENOMEM); @@ -575,12 +576,12 @@ static struct p9_conn *p9_conn_create(struct p9_client *client) n = p9_fd_poll(client, &m->pt); if (n & POLLIN) { - P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can read\n", m); set_bit(Rpending, &m->wsched); } if (n & POLLOUT) { - P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can write\n", m); set_bit(Wpending, &m->wsched); } @@ -602,7 +603,7 @@ static void p9_poll_mux(struct p9_conn *m) n = p9_fd_poll(m->client, NULL); if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { - P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n); + P9_DPRINTK(P9_DEBUG_TRANS, "error mux %p err %d\n", m, n); if (n >= 0) n = -ECONNRESET; p9_conn_cancel(m, n); @@ -610,19 +611,19 @@ static void p9_poll_mux(struct p9_conn *m) if (n & POLLIN) { set_bit(Rpending, &m->wsched); - P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can read\n", m); if (!test_and_set_bit(Rworksched, &m->wsched)) { - P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "sched read work %p\n", m); queue_work(p9_mux_wq, &m->rq); } } if (n & POLLOUT) { set_bit(Wpending, &m->wsched); - P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can write\n", m); if ((m->wsize || !list_empty(&m->unsent_req_list)) && !test_and_set_bit(Wworksched, &m->wsched)) { - P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m); queue_work(p9_mux_wq, &m->wq); } } @@ -645,8 +646,8 @@ static int p9_fd_request(struct p9_client *client, struct p9_req_t *req) struct p9_trans_fd *ts = client->trans; struct p9_conn *m = ts->conn; - P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current, - req->tc, req->tc->id); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p task %p tcall %p id %d\n", m, + current, req->tc, req->tc->id); if (m->err < 0) return m->err; @@ -672,19 +673,12 @@ static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req) struct p9_trans_fd *ts = client->trans; struct p9_conn *m = ts->conn; - P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p\n", m, req); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p req %p\n", m, req); spin_lock(&client->lock); list_del(&req->req_list); spin_unlock(&client->lock); - /* if a response was received for a request, do nothing */ - if (req->rc || req->t_err) { - P9_DPRINTK(P9_DEBUG_MUX, - "mux %p req %p response already received\n", m, req); - return 0; - } - if (req->status == REQ_STATUS_UNSENT) { req->status = REQ_STATUS_FLSHD; return 0; @@ -809,7 +803,7 @@ static int p9_socket_open(struct p9_client *client, struct socket *csocket) static void p9_conn_destroy(struct p9_conn *m) { - P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m, + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p prev %p next %p\n", m, m->mux_list.prev, m->mux_list.next); p9_mux_poll_stop(m); @@ -1060,7 +1054,7 @@ static int p9_poll_proc(void *a) { unsigned long flags; - P9_DPRINTK(P9_DEBUG_MUX, "start %p\n", current); + P9_DPRINTK(P9_DEBUG_TRANS, "start %p\n", current); repeat: spin_lock_irqsave(&p9_poll_lock, flags); while (!list_empty(&p9_poll_pending_list)) { @@ -1078,7 +1072,7 @@ static int p9_poll_proc(void *a) set_current_state(TASK_INTERRUPTIBLE); if (list_empty(&p9_poll_pending_list)) { - P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n"); + P9_DPRINTK(P9_DEBUG_TRANS, "sleeping...\n"); schedule(); } __set_current_state(TASK_RUNNING); @@ -1086,7 +1080,7 @@ static int p9_poll_proc(void *a) if (!kthread_should_stop()) goto repeat; - P9_DPRINTK(P9_DEBUG_MUX, "finish\n"); + P9_DPRINTK(P9_DEBUG_TRANS, "finish\n"); return 0; } diff --git a/net/9p/util.c b/net/9p/util.c index 958fc58cd1ff..dc4ec05ad93d 100644 --- a/net/9p/util.c +++ b/net/9p/util.c @@ -105,6 +105,7 @@ retry: else if (error) return -1; + P9_DPRINTK(P9_DEBUG_MUX, " id %d pool %p\n", i, p); return i; } EXPORT_SYMBOL(p9_idpool_get); @@ -121,6 +122,9 @@ EXPORT_SYMBOL(p9_idpool_get); void p9_idpool_put(int id, struct p9_idpool *p) { unsigned long flags; + + P9_DPRINTK(P9_DEBUG_MUX, " id %d pool %p\n", id, p); + spin_lock_irqsave(&p->lock, flags); idr_remove(&p->pool, id); spin_unlock_irqrestore(&p->lock, flags); -- cgit v1.2.3 From 7eb923b80c8ce16697129fb2dcdfaeabf83f0dbc Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Fri, 17 Oct 2008 12:45:40 -0500 Subject: 9p: add more conservative locking During the reorganization some of the multi-theaded locking assumptions were accidently relaxed. This patch moves us back towards a more conservative locking strategy. Signed-off-by: Eric Van Hensbergen --- net/9p/trans_fd.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'net/9p/trans_fd.c') diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index e8ebe2cb7e8b..be65d8242fd2 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -188,8 +188,16 @@ static void p9_conn_cancel(struct p9_conn *m, int err) LIST_HEAD(cancel_list); P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err); - m->err = err; + spin_lock_irqsave(&m->client->lock, flags); + + if (m->err) { + spin_unlock_irqrestore(&m->client->lock, flags); + return; + } + + m->err = err; + list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { req->status = REQ_STATUS_ERROR; if (!req->t_err) @@ -352,8 +360,9 @@ static void p9_read_work(struct work_struct *work) /* not an else because some packets (like clunk) have no payload */ if ((m->req) && (m->rpos == m->rsize)) { /* packet is read in */ P9_DPRINTK(P9_DEBUG_TRANS, "got new packet\n"); - + spin_lock(&m->client->lock); list_del(&m->req->req_list); + spin_unlock(&m->client->lock); p9_client_cb(m->client, m->req); m->rbuf = NULL; @@ -651,9 +660,8 @@ static int p9_fd_request(struct p9_client *client, struct p9_req_t *req) if (m->err < 0) return m->err; - req->status = REQ_STATUS_UNSENT; - spin_lock(&client->lock); + req->status = REQ_STATUS_UNSENT; list_add_tail(&req->req_list, &m->unsent_req_list); spin_unlock(&client->lock); @@ -672,19 +680,21 @@ static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req) { struct p9_trans_fd *ts = client->trans; struct p9_conn *m = ts->conn; + int ret = 1; P9_DPRINTK(P9_DEBUG_TRANS, "mux %p req %p\n", m, req); spin_lock(&client->lock); list_del(&req->req_list); - spin_unlock(&client->lock); if (req->status == REQ_STATUS_UNSENT) { req->status = REQ_STATUS_FLSHD; - return 0; + ret = 0; } - return 1; + spin_unlock(&client->lock); + + return ret; } /** -- cgit v1.2.3