From 992b3f1dbeec401e19a80bdb8c81e5df5381f4c5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 13 Oct 2008 18:45:25 -0500 Subject: [PATCH 01/26] 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(-) 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) -{ - 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"); - } - - 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; - } - } - } - - if (i >= ARRAY_SIZE(p9_mux_poll_tasks)) { - if (vptlast == NULL) { - mutex_unlock(&p9_mux_task_lock); - return -ENOMEM; - } - - 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) { + unsigned long flags; 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; + for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { + struct p9_poll_wait *pwait = &m->poll_wait[i]; + + if (pwait->wait_addr) { + remove_wait_queue(pwait->wait_addr, &pwait->wait); + pwait->wait_addr = 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); From 8b81ef589ad1483dd977ef47fe00d4ce4d91a0ab Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:25 -0500 Subject: [PATCH 02/26] 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(-) 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, From bead27f0a87f4055f6a0fd69ded9eacced485618 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:24 -0500 Subject: [PATCH 03/26] 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(-) 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 From 5503ac565998837350f3ee1cc344c36143ea2386 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:24 -0500 Subject: [PATCH 04/26] 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 | 860 ++++++++++++++++++++++------------------------ 2 files changed, 495 insertions(+), 548 deletions(-) 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,303 +247,38 @@ static void p9_mux_poll_stop(struct p9_conn *m) } /** - * 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. - */ - -static struct p9_conn *p9_conn_create(struct p9_client *client) -{ - 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); - - 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); - 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); - - 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 (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; - } - } - - return m; -} - -/** - * p9_mux_destroy - cancels all pending requests and frees mux resources - * @m: mux to destroy + * p9_conn_cancel - cancel all pending requests with error + * @m: mux data + * @err: error code * */ -static void p9_conn_destroy(struct p9_conn *m) +void p9_conn_cancel(struct p9_conn *m, int err) { - P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m, - m->mux_list.prev, m->mux_list.next); + struct p9_req *req, *rtmp; + LIST_HEAD(cancel_list); - p9_mux_poll_stop(m); - cancel_work_sync(&m->rq); - cancel_work_sync(&m->wq); - - p9_conn_cancel(m, -ECONNRESET); - - m->client = NULL; - p9_idpool_destroy(m->tagpool); - 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 - * @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_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; - - for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { - if (m->poll_wait[i].wait_addr == NULL) { - pwait = &m->poll_wait[i]; - break; - } + 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); } - - if (!pwait) { - P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n"); - return; + list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { + list_move(&req->req_list, &cancel_list); } + spin_unlock(&m->lock); - if (!wait_address) { - P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n"); - pwait->wait_addr = ERR_PTR(-EIO); - return; - } + list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { + list_del(&req->req_list); + if (!req->err) + req->err = err; - pwait->conn = m; - pwait->wait_addr = wait_address; - init_waitqueue_func_entry(&pwait->wait, p9_pollwake); - add_wait_queue(wait_address, &pwait->wait); -} - -/** - * 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); - } - } - - 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); - } - } -} - -/** - * 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; -} - -/** - * p9_write_work - called when a transport can send some data - * @work: container for work to be done - * - */ - -static void p9_write_work(struct work_struct *work) -{ - int n, err; - struct p9_conn *m; - struct p9_req *req; - - m = container_of(work, struct p9_conn, wq); - - if (m->err < 0) { - clear_bit(Wworksched, &m->wsched); - return; - } - - if (!m->wsize) { - if (list_empty(&m->unsent_req_list)) { - clear_bit(Wworksched, &m->wsched); - return; - } - - spin_lock(&m->lock); -again: - req = list_entry(m->unsent_req_list.next, struct p9_req, - req_list); - 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->wpos = 0; - spin_unlock(&m->lock); - } - - 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->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); - return; - } - - if (err < 0) - goto error; - else if (err == 0) { - err = -EREMOTEIO; - goto error; - } - - m->wpos += err; - if (m->wpos == m->wsize) - m->wpos = m->wsize = 0; - - if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) { - if (test_and_clear_bit(Wpending, &m->wsched)) - n = POLLOUT; + if (req->cb) + (*req->cb) (req, req->cba); else - n = p9_fd_poll(m->client, NULL); - - if (n & POLLOUT) { - P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); - queue_work(p9_mux_wq, &m->wq); - } else - clear_bit(Wworksched, &m->wsched); - } else - clear_bit(Wworksched, &m->wsched); - - return; - -error: - p9_conn_cancel(m, err); - clear_bit(Wworksched, &m->wsched); + kfree(req->rcall); + } } static void process_request(struct p9_conn *m, struct p9_req *req) @@ -599,6 +314,66 @@ static void process_request(struct p9_conn *m, struct p9_req *req) } } +static unsigned int +p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt) +{ + 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; + + ret = ts->rd->f_op->poll(ts->rd, pt); + if (ret < 0) + return ret; + + 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_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_read_work - called when there is some data to be read from a transport * @work: container of work to be done @@ -748,6 +523,275 @@ error: 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_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; +} + +/** + * p9_write_work - called when a transport can send some data + * @work: container for work to be done + * + */ + +static void p9_write_work(struct work_struct *work) +{ + int n, err; + struct p9_conn *m; + struct p9_req *req; + + m = container_of(work, struct p9_conn, wq); + + if (m->err < 0) { + clear_bit(Wworksched, &m->wsched); + return; + } + + if (!m->wsize) { + if (list_empty(&m->unsent_req_list)) { + clear_bit(Wworksched, &m->wsched); + return; + } + + spin_lock(&m->lock); +again: + req = list_entry(m->unsent_req_list.next, struct p9_req, + req_list); + 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->wpos = 0; + spin_unlock(&m->lock); + } + + 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->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); + return; + } + + if (err < 0) + goto error; + else if (err == 0) { + err = -EREMOTEIO; + goto error; + } + + m->wpos += err; + if (m->wpos == m->wsize) + m->wpos = m->wsize = 0; + + if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) { + if (test_and_clear_bit(Wpending, &m->wsched)) + n = POLLOUT; + else + n = p9_fd_poll(m->client, NULL); + + if (n & POLLOUT) { + P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); + queue_work(p9_mux_wq, &m->wq); + } else + clear_bit(Wworksched, &m->wsched); + } else + clear_bit(Wworksched, &m->wsched); + + return; + +error: + p9_conn_cancel(m, err); + clear_bit(Wworksched, &m->wsched); +} + +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 + * @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_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; + + 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 (!pwait) { + P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n"); + 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); + add_wait_queue(wait_address, &pwait->wait); +} + +/** + * 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. + */ + +static struct p9_conn *p9_conn_create(struct p9_client *client) +{ + 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); + + 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); + 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); + + 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 (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; + } + } + + return m; +} + +/** + * 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); + } + } + + 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); + } + } +} + /** * p9_send_request - send 9P request * The function can sleep until the request is scheduled for sending. @@ -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 + * p9_mux_destroy - cancels all pending requests and frees mux resources + * @m: mux to destroy * */ -static int p9_fd_read(struct p9_client *client, void *v, int len) +static void p9_conn_destroy(struct p9_conn *m) { - int ret; - struct p9_trans_fd *ts = NULL; + P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m, + m->mux_list.prev, m->mux_list.next); - if (client && client->status != Disconnected) - ts = client->trans; + p9_mux_poll_stop(m); + cancel_work_sync(&m->rq); + cancel_work_sync(&m->wq); - if (!ts) - return -EREMOTEIO; + p9_conn_cancel(m, -ECONNRESET); - 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 - * - */ - -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) -{ - 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; - - ret = ts->rd->f_op->poll(ts->rd, pt); - if (ret < 0) - return ret; - - 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; + 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"); From 21c003687e2d1c589cf177a3ba17fd439af94850 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:24 -0500 Subject: [PATCH 05/26] 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(-) 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) From 044c7768841f1ef39f951972d3c1e6537a535030 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:23 -0500 Subject: [PATCH 06/26] 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(-) 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); From fea511a644fb0fb938309c6ab286725ac31b87e2 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:23 -0500 Subject: [PATCH 07/26] 9p: move request management to client code The virtio transport uses a simplified request management system that I want to use for all transports. This patch adapts and moves the exisiting code for managing requests to the client common code. Later patches will apply these mechanisms to the other transports. Signed-off-by: Eric Van Hensbergen --- include/net/9p/client.h | 77 ++++++++++++++++++++ net/9p/client.c | 152 ++++++++++++++++++++++++++++++++++++++++ net/9p/trans_virtio.c | 136 +++-------------------------------- 3 files changed, 238 insertions(+), 127 deletions(-) diff --git a/include/net/9p/client.h b/include/net/9p/client.h index c35fb548e7cf..140cf1d58452 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -26,6 +26,9 @@ #ifndef NET_9P_CLIENT_H #define NET_9P_CLIENT_H +/* Number of requests per row */ +#define P9_ROW_MAXTAG 255 + /** * enum p9_trans_status - different states of underlying transports * @Connected: transport is connected and healthy @@ -42,6 +45,62 @@ enum p9_trans_status { Hung, }; +/** + * 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_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 + * + * 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 + * id allocation. + * + */ + +enum p9_req_status_t { + REQ_STATUS_IDLE, + REQ_STATUS_ALLOC, + REQ_STATUS_SENT, + REQ_STATUS_FLSH, + REQ_STATUS_RCVD, + REQ_STATUS_FLSHD, + REQ_STATUS_ERROR, +}; + +/** + * struct p9_req_t - request slots + * @status: status of this request slot + * @t_err: transport error + * @wq: wait_queue for the client to block on for this request + * @tc: the request fcall structure + * @rc: the response fcall structure + * @aux: transport specific data (provided for trans_fd migration) + * + * Transport use an array to track outstanding requests + * instead of a list. While this may incurr overhead during initial + * allocation or expansion, it makes request lookup much easier as the + * tag id is a index into an array. (We use tag+1 so that we can accomodate + * the -1 tag for the T_VERSION request). + * This also has the nice effect of only having to allocate wait_queues + * once, instead of constantly allocating and freeing them. Its possible + * other resources could benefit from this scheme as well. + * + */ + +struct p9_req_t { + int status; + int t_err; + wait_queue_head_t *wq; + struct p9_fcall *tc; + struct p9_fcall *rc; + u16 flush_tag; + void *aux; +}; + /** * struct p9_client - per client instance state * @lock: protect @fidlist @@ -52,9 +111,20 @@ enum p9_trans_status { * @conn: connection state information used by trans_fd * @fidpool: fid handle accounting for session * @fidlist: List of active fid handles + * @tagpool - transaction id accounting for session + * @reqs - 2D array of requests + * @max_tag - current maximum tag id allocated * * The client structure is used to keep track of various per-client * state that has been instantiated. + * In order to minimize per-transaction overhead we use a + * simple array to lookup requests instead of a hash table + * or linked list. In order to support larger number of + * transactions, we make this a 2D array, allocating new rows + * when we need to grow the total number of the transactions. + * + * Each row is 256 requests and we'll support up to 256 rows for + * a total of 64k concurrent requests per session. * * Bugs: duplicated data and potentially unnecessary elements. */ @@ -70,6 +140,10 @@ struct p9_client { struct p9_idpool *fidpool; struct list_head fidlist; + + struct p9_idpool *tagpool; + struct p9_req_t *reqs[P9_ROW_MAXTAG]; + int max_tag; }; /** @@ -131,4 +205,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); + #endif /* NET_9P_CLIENT_H */ diff --git a/net/9p/client.c b/net/9p/client.c index 712d4f336adc..867031934f75 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -120,6 +120,154 @@ static int parse_opts(char *opts, struct p9_client *clnt) return ret; } +/** + * p9_tag_alloc - lookup/allocate a request by tag + * @c: client session to lookup tag within + * @tag: numeric id for transaction + * + * this is a simple array lookup, but will grow the + * request_slots as necessary to accomodate transaction + * ids which did not previously have a slot. + * + * this code relies on the client spinlock to manage locks, its + * possible we should switch to something else, but I'd rather + * stick with something low-overhead for the common case. + * + */ + +struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) +{ + unsigned long flags; + int row, col; + + /* This looks up the original request by tag so we know which + * buffer to read the data into */ + tag++; + + if (tag >= c->max_tag) { + spin_lock_irqsave(&c->lock, flags); + /* check again since original check was outside of lock */ + while (tag >= c->max_tag) { + row = (tag / P9_ROW_MAXTAG); + c->reqs[row] = kcalloc(P9_ROW_MAXTAG, + sizeof(struct p9_req_t), GFP_ATOMIC); + + if (!c->reqs[row]) { + printk(KERN_ERR "Couldn't grow tag array\n"); + BUG(); + } + 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->max_tag += P9_ROW_MAXTAG; + } + spin_unlock_irqrestore(&c->lock, flags); + } + 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; + + return &c->reqs[row][col]; +} +EXPORT_SYMBOL(p9_tag_alloc); + +/** + * p9_tag_lookup - lookup a request by tag + * @c: client session to lookup tag within + * @tag: numeric id for transaction + * + */ + +struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag) +{ + int row, col; + + /* This looks up the original request by tag so we know which + * buffer to read the data into */ + tag++; + + BUG_ON(tag >= c->max_tag); + + row = tag / P9_ROW_MAXTAG; + col = tag % P9_ROW_MAXTAG; + + return &c->reqs[row][col]; +} +EXPORT_SYMBOL(p9_tag_lookup); + +/** + * p9_tag_init - setup tags structure and contents + * @tags: tags structure from the client struct + * + * This initializes the tags structure for each client instance. + * + */ + +static int p9_tag_init(struct p9_client *c) +{ + int err = 0; + + c->tagpool = p9_idpool_create(); + if (IS_ERR(c->tagpool)) { + err = PTR_ERR(c->tagpool); + c->tagpool = NULL; + goto error; + } + + p9_idpool_get(c->tagpool); /* reserve tag 0 */ + + c->max_tag = 0; +error: + return err; +} + +/** + * p9_tag_cleanup - cleans up tags structure and reclaims resources + * @tags: tags structure from the client struct + * + * This frees resources associated with the tags structure + * + */ +static void p9_tag_cleanup(struct p9_client *c) +{ + int row, col; + + /* check to insure all requests are idle */ + for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { + for (col = 0; col < P9_ROW_MAXTAG; col++) { + if (c->reqs[row][col].status != REQ_STATUS_IDLE) { + P9_DPRINTK(P9_DEBUG_MUX, + "Attempting to cleanup non-free tag %d,%d\n", + row, col); + /* TODO: delay execution of cleanup */ + return; + } + } + } + + if (c->tagpool) + p9_idpool_destroy(c->tagpool); + + /* free requests associated with tags */ + for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { + for (col = 0; col < P9_ROW_MAXTAG; col++) + kfree(c->reqs[row][col].wq); + kfree(c->reqs[row]); + } + c->max_tag = 0; +} + static struct p9_fid *p9_fid_create(struct p9_client *clnt) { int err; @@ -209,6 +357,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options) goto error; } + p9_tag_init(clnt); + err = parse_opts(options, clnt); if (err < 0) goto error; @@ -285,6 +435,8 @@ void p9_client_destroy(struct p9_client *clnt) if (clnt->fidpool) p9_idpool_destroy(clnt->fidpool); + p9_tag_cleanup(clnt); + kfree(clnt); } EXPORT_SYMBOL(p9_client_destroy); diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 72493f04a76d..36bce45e4e44 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -1,12 +1,10 @@ /* - * The Guest 9p transport driver + * The Virtio 9p transport driver * * This is a block based transport driver based on the lguest block driver * code. * - */ -/* - * Copyright (C) 2007 Eric Van Hensbergen, IBM Corporation + * Copyright (C) 2007, 2008 Eric Van Hensbergen, IBM Corporation * * Based on virtio console driver * Copyright (C) 2006, 2007 Rusty Russell, IBM Corporation @@ -54,49 +52,6 @@ static DEFINE_MUTEX(virtio_9p_lock); /* global which tracks highest initialized channel */ static int chan_index; -#define P9_INIT_MAXTAG 16 - -/** - * enum p9_req_status_t - virtio request status - * @REQ_STATUS_IDLE: request slot unused - * @REQ_STATUS_SENT: request sent to server - * @REQ_STATUS_RCVD: response received from server - * @REQ_STATUS_FLSH: request has been flushed - * - * 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 - * id allocation. - * - */ - -enum p9_req_status_t { - REQ_STATUS_IDLE, - REQ_STATUS_SENT, - REQ_STATUS_RCVD, - REQ_STATUS_FLSH, -}; - -/** - * struct p9_req_t - virtio request slots - * @status: status of this request slot - * @wq: wait_queue for the client to block on for this request - * - * The virtio transport uses an array to track outstanding requests - * instead of a list. While this may incurr overhead during initial - * allocation or expansion, it makes request lookup much easier as the - * tag id is a index into an array. (We use tag+1 so that we can accomodate - * the -1 tag for the T_VERSION request). - * This also has the nice effect of only having to allocate wait_queues - * once, instead of constantly allocating and freeing them. Its possible - * other resources could benefit from this scheme as well. - * - */ - -struct p9_req_t { - int status; - wait_queue_head_t *wq; -}; - /** * struct virtio_chan - per-instance transport information * @initialized: whether the channel is initialized @@ -121,67 +76,14 @@ static struct virtio_chan { spinlock_t lock; + struct p9_client *client; struct virtio_device *vdev; struct virtqueue *vq; - struct p9_idpool *tagpool; - struct p9_req_t *reqs; - int max_tag; - /* Scatterlist: can be too big for stack. */ struct scatterlist sg[VIRTQUEUE_NUM]; } channels[MAX_9P_CHAN]; -/** - * p9_lookup_tag - Lookup requests by tag - * @c: virtio channel to lookup tag within - * @tag: numeric id for transaction - * - * this is a simple array lookup, but will grow the - * request_slots as necessary to accomodate transaction - * ids which did not previously have a slot. - * - * Bugs: there is currently no upper limit on request slots set - * here, but that should be constrained by the id accounting. - */ - -static struct p9_req_t *p9_lookup_tag(struct virtio_chan *c, u16 tag) -{ - /* This looks up the original request by tag so we know which - * buffer to read the data into */ - tag++; - - while (tag >= c->max_tag) { - int old_max = c->max_tag; - int count; - - if (c->max_tag) - c->max_tag *= 2; - else - c->max_tag = P9_INIT_MAXTAG; - - c->reqs = krealloc(c->reqs, sizeof(struct p9_req_t)*c->max_tag, - GFP_ATOMIC); - if (!c->reqs) { - printk(KERN_ERR "Couldn't grow tag array\n"); - BUG(); - } - for (count = old_max; count < c->max_tag; count++) { - c->reqs[count].status = REQ_STATUS_IDLE; - c->reqs[count].wq = kmalloc(sizeof(wait_queue_head_t), - GFP_ATOMIC); - if (!c->reqs[count].wq) { - printk(KERN_ERR "Couldn't grow tag array\n"); - BUG(); - } - init_waitqueue_head(c->reqs[count].wq); - } - } - - return &c->reqs[tag]; -} - - /* How many bytes left in this page. */ static unsigned int rest_of_page(void *data) { @@ -200,22 +102,10 @@ static unsigned int rest_of_page(void *data) static void p9_virtio_close(struct p9_client *client) { struct virtio_chan *chan = client->trans; - int count; - unsigned long flags; - - spin_lock_irqsave(&chan->lock, flags); - p9_idpool_destroy(chan->tagpool); - for (count = 0; count < chan->max_tag; count++) - kfree(chan->reqs[count].wq); - kfree(chan->reqs); - chan->max_tag = 0; - spin_unlock_irqrestore(&chan->lock, flags); mutex_lock(&virtio_9p_lock); chan->inuse = false; mutex_unlock(&virtio_9p_lock); - - client->trans = NULL; } /** @@ -241,7 +131,7 @@ static void req_done(struct virtqueue *vq) spin_lock_irqsave(&chan->lock, flags); while ((rc = chan->vq->vq_ops->get_buf(chan->vq, &len)) != NULL) { - req = p9_lookup_tag(chan, rc->tag); + req = p9_tag_lookup(chan->client, rc->tag); req->status = REQ_STATUS_RCVD; wake_up(req->wq); } @@ -311,13 +201,13 @@ p9_virtio_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) n = P9_NOTAG; if (tc->id != P9_TVERSION) { - n = p9_idpool_get(chan->tagpool); + n = p9_idpool_get(c->tagpool); if (n < 0) return -ENOMEM; } spin_lock_irqsave(&chan->lock, flags); - req = p9_lookup_tag(chan, n); + req = p9_tag_alloc(c, n); spin_unlock_irqrestore(&chan->lock, flags); p9_set_tag(tc, n); @@ -357,8 +247,8 @@ p9_virtio_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) } #endif - if (n != P9_NOTAG && p9_idpool_check(n, chan->tagpool)) - p9_idpool_put(n, chan->tagpool); + if (n != P9_NOTAG && p9_idpool_check(n, c->tagpool)) + p9_idpool_put(n, c->tagpool); req->status = REQ_STATUS_IDLE; @@ -463,16 +353,8 @@ p9_virtio_create(struct p9_client *client, const char *devname, char *args) return -ENODEV; } - chan->tagpool = p9_idpool_create(); - if (IS_ERR(chan->tagpool)) { - printk(KERN_ERR "9p: couldn't allocate tagpool\n"); - return -ENOMEM; - } - p9_idpool_get(chan->tagpool); /* reserve tag 0 */ - chan->max_tag = 0; - chan->reqs = NULL; - client->trans = (void *)chan; + chan->client = client; return 0; } From ff683452f7bc52d7fd653cf5e67b1134555734c7 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:22 -0500 Subject: [PATCH 08/26] 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(-) 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); } From 673d62cdaac6ffbce980a349d3174b3929ceb9e5 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:22 -0500 Subject: [PATCH 09/26] 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(-) 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_client *, struct p9_req_t *); -static void p9_conn_rpc_cb(struct p9_req *req); - -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; } From 1b0a763bdd5ed467d0e03b88e045000c749303fb Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:22 -0500 Subject: [PATCH 10/26] 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 | 131 ++++++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 64 deletions(-) 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; - } - - 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); + m->req->rc->id, m->req->rc->tag); - req = p9_tag_lookup(m->client, rcall->tag); + m->rbuf = NULL; + m->rpos = 0; + m->rsize = 0; - if (req) { - 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->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); + 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; } 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); From 91b8534fa8f5e01f249b1bf8df0a2540053549ad Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 18:45:21 -0500 Subject: [PATCH 11/26] 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(-) 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; + struct virtio_chan *chan = client->trans; + char *rdata = (char *)req->rc+sizeof(struct p9_fcall); - if (*rc == NULL) { - *rc = kmalloc(sizeof(struct p9_fcall) + c->msize, GFP_KERNEL); - if (!*rc) - return -ENOMEM; - } + P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); - 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); - - 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, 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, From 95820a36516d12dcb49d066dd3d5b187a2557612 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 13 Oct 2008 18:45:20 -0500 Subject: [PATCH 12/26] 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(-) 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; } From 0fc9655ec67ec5d4dfd08e469e0e9f0a494bf5bc Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 20:36:17 -0500 Subject: [PATCH 13/26] 9p: consolidate read/write functions Currently there are two separate versions of read and write. One for dealing with user buffers and the other for dealing with kernel buffers. There is a tremendous amount of code duplication in the otherwise identical versions of these functions. This patch adds an additional user buffer parameter to read and write and conditionalizes handling of the buffer on whether the kernel buffer or the user buffer is populated. Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_file.c | 4 +- include/net/9p/client.h | 10 ++- net/9p/client.c | 156 ++++++++-------------------------------- 3 files changed, 37 insertions(+), 133 deletions(-) diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 52944d2249a4..3819a195de8f 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -136,7 +136,7 @@ v9fs_file_read(struct file *filp, char __user * data, size_t count, P9_DPRINTK(P9_DEBUG_VFS, "\n"); fid = filp->private_data; - ret = p9_client_uread(fid, data, *offset, count); + ret = p9_client_read(fid, NULL, data, *offset, count); if (ret > 0) *offset += ret; @@ -164,7 +164,7 @@ v9fs_file_write(struct file *filp, const char __user * data, (int)count, (int)*offset); fid = filp->private_data; - ret = p9_client_uwrite(fid, data, *offset, count); + ret = p9_client_write(fid, NULL, data, *offset, count); if (ret > 0) { invalidate_inode_pages2_range(inode->i_mapping, *offset, *offset+ret); diff --git a/include/net/9p/client.h b/include/net/9p/client.h index 6a71d9067818..c70a0f0b448d 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -201,13 +201,11 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, char *extension); int p9_client_clunk(struct p9_fid *fid); int p9_client_remove(struct p9_fid *fid); -int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count); +int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, + u64 offset, u32 count); int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count); -int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count); -int p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, - u32 count); -int p9_client_uwrite(struct p9_fid *fid, const char __user *data, 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); int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst); struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset); diff --git a/net/9p/client.c b/net/9p/client.c index 29934febecdb..5fc3aa1eb39b 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -1016,7 +1016,9 @@ done: } EXPORT_SYMBOL(p9_client_remove); -int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count) +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; @@ -1053,9 +1055,21 @@ int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count) if (n > count) n = count; - memmove(data, rc->params.rread.data, n); + if (data) { + memmove(data, rc->params.rread.data, n); + data += n; + } + + if (udata) { + err = copy_to_user(udata, rc->params.rread.data, n); + if (err) { + err = -EFAULT; + goto error; + } + udata += n; + } + count -= n; - data += n; offset += n; total += n; kfree(tc); @@ -1073,7 +1087,9 @@ error: } EXPORT_SYMBOL(p9_client_read); -int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count) +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; @@ -1095,7 +1111,10 @@ int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count) if (count < rsize) rsize = count; - tc = p9_create_twrite(fid->fid, offset, rsize, data); + 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; @@ -1108,7 +1127,12 @@ int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count) n = rc->params.rread.count; count -= n; - data += n; + + if (data) + data += n; + else + udata += n; + offset += n; total += n; kfree(tc); @@ -1126,124 +1150,6 @@ error: } EXPORT_SYMBOL(p9_client_write); -int -p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count) -{ - int err, n, rsize, total; - struct p9_fcall *tc, *rc; - struct p9_client *clnt; - - P9_DPRINTK(P9_DEBUG_9P, "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; - - rsize = fid->iounit; - if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) - rsize = clnt->msize - P9_IOHDRSZ; - - do { - 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; - } - - err = p9_client_rpc(clnt, tc, &rc); - if (err) - goto error; - - n = rc->params.rread.count; - if (n > count) - n = count; - - err = copy_to_user(data, rc->params.rread.data, n); - if (err) { - err = -EFAULT; - goto error; - } - - count -= n; - data += n; - offset += n; - total += n; - kfree(tc); - tc = NULL; - kfree(rc); - rc = NULL; - } while (count > 0 && n == rsize); - - return total; - -error: - kfree(tc); - kfree(rc); - return err; -} -EXPORT_SYMBOL(p9_client_uread); - -int -p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset, - u32 count) -{ - int err, n, rsize, total; - struct p9_fcall *tc, *rc; - struct p9_client *clnt; - - P9_DPRINTK(P9_DEBUG_9P, "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; - - rsize = fid->iounit; - if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) - rsize = clnt->msize - P9_IOHDRSZ; - - do { - if (count < rsize) - rsize = count; - - tc = p9_create_twrite_u(fid->fid, offset, rsize, data); - 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; - data += n; - offset += n; - total += n; - kfree(tc); - tc = NULL; - kfree(rc); - rc = NULL; - } while (count > 0); - - return total; - -error: - kfree(tc); - kfree(rc); - return err; -} -EXPORT_SYMBOL(p9_client_uwrite); - int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count) { int n, total; @@ -1253,7 +1159,7 @@ int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count) n = 0; total = 0; while (count) { - n = p9_client_read(fid, data, offset, count); + n = p9_client_read(fid, data, NULL, offset, count); if (n <= 0) break; From fbedadc16e5c888e4df9df3b1757de4993508d35 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 20:36:16 -0500 Subject: [PATCH 14/26] 9p: move readn meta-function from client to fs layer There are a couple of methods in the client code which aren't actually wire operations. To keep things organized cleaner, these operations are being moved to the fs layer. This patch moves the readn meta-function (which executes multiple wire reads until a buffer is full) to the fs layer. Signed-off-by: Eric Van Hensbergen --- fs/9p/v9fs.c | 2 +- fs/9p/v9fs_vfs.h | 2 ++ fs/9p/vfs_addr.c | 5 +--- fs/9p/vfs_file.c | 57 ++++++++++++++++++++++++++++++++++++++--- include/net/9p/client.h | 1 - net/9p/client.c | 26 ------------------- 6 files changed, 57 insertions(+), 36 deletions(-) diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index b6b85cf01e0d..24eb01087b6d 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -234,7 +234,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, if (!v9ses->clnt->dotu) v9ses->flags &= ~V9FS_EXTENDED; - v9ses->maxdata = v9ses->clnt->msize; + v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ; /* for legacy mode, fall back to V9FS_ACCESS_ANY */ if (!v9fs_extended(v9ses) && diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index 57997fa14e69..046cff377f10 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h @@ -52,3 +52,5 @@ int v9fs_file_open(struct inode *inode, struct file *file); void v9fs_inode2stat(struct inode *inode, struct p9_stat *stat); void v9fs_dentry_release(struct dentry *); int v9fs_uflags2omode(int uflags, int extended); + +ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index 97d3aed57983..6fcb1e7095cf 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c @@ -38,7 +38,6 @@ #include "v9fs.h" #include "v9fs_vfs.h" -#include "fid.h" /** * v9fs_vfs_readpage - read an entire page in from 9P @@ -53,14 +52,12 @@ static int v9fs_vfs_readpage(struct file *filp, struct page *page) int retval; loff_t offset; char *buffer; - struct p9_fid *fid; P9_DPRINTK(P9_DEBUG_VFS, "\n"); - fid = filp->private_data; buffer = kmap(page); offset = page_offset(page); - retval = p9_client_readn(fid, buffer, offset, PAGE_CACHE_SIZE); + retval = v9fs_file_readn(filp, buffer, NULL, offset, PAGE_CACHE_SIZE); if (retval < 0) goto done; diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 3819a195de8f..4d6d7657fb75 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -120,23 +120,72 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) } /** - * v9fs_file_read - read from a file + * v9fs_file_readn - read from a file * @filp: file pointer to read * @data: data buffer to read data into + * @udata: user data buffer to read data into * @count: size of buffer * @offset: offset at which to read data * */ + +ssize_t +v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count, + u64 offset) +{ + int n, total; + struct p9_fid *fid = filp->private_data; + + P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, + (long long unsigned) offset, count); + + n = 0; + total = 0; + do { + n = p9_client_read(fid, data, udata, offset, count); + if (n <= 0) + break; + + if (data) + data += n; + if (udata) + udata += n; + + offset += n; + count -= n; + total += n; + } while (count > 0 && n == (fid->clnt->msize - P9_IOHDRSZ)); + + if (n < 0) + total = n; + + return total; +} + +/** + * v9fs_file_read - read from a file + * @filp: file pointer to read + * @udata: user data buffer to read data into + * @count: size of buffer + * @offset: offset at which to read data + * + */ + static ssize_t -v9fs_file_read(struct file *filp, char __user * data, size_t count, +v9fs_file_read(struct file *filp, char __user *udata, size_t count, loff_t * offset) { int ret; struct p9_fid *fid; - P9_DPRINTK(P9_DEBUG_VFS, "\n"); + P9_DPRINTK(P9_DEBUG_VFS, "count %d offset %lld\n", count, *offset); fid = filp->private_data; - ret = p9_client_read(fid, NULL, data, *offset, count); + + if (count > (fid->clnt->msize - P9_IOHDRSZ)) + ret = v9fs_file_readn(filp, NULL, udata, count, *offset); + else + ret = p9_client_read(fid, NULL, udata, *offset, count); + if (ret > 0) *offset += ret; diff --git a/include/net/9p/client.h b/include/net/9p/client.h index c70a0f0b448d..bb8b0ede132d 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -203,7 +203,6 @@ int p9_client_clunk(struct p9_fid *fid); int p9_client_remove(struct p9_fid *fid); int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, u32 count); -int p9_client_readn(struct p9_fid *fid, char *data, 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); diff --git a/net/9p/client.c b/net/9p/client.c index 5fc3aa1eb39b..d5ea042eabb0 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -1150,32 +1150,6 @@ error: } EXPORT_SYMBOL(p9_client_write); -int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count) -{ - int n, total; - - P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, - (long long unsigned) offset, count); - n = 0; - total = 0; - while (count) { - n = p9_client_read(fid, data, NULL, offset, count); - if (n <= 0) - break; - - data += n; - offset += n; - count -= n; - total += n; - } - - if (n < 0) - total = n; - - return total; -} -EXPORT_SYMBOL(p9_client_readn); - static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu) { int n; From dfb0ec2e13a906ff19a0bbfa9208caab50cfc2e3 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 20:36:16 -0500 Subject: [PATCH 15/26] 9p: adjust 9p vfs write operation Currently, the 9p net wire operation ensures that all data is sent by sending multiple packets if the data requested is larger than the msize. This is better handled in the vfs code so that we can simplify wire operations to being concerned with only putting data onto and taking data off of the wire. Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_file.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 4d6d7657fb75..3fd28bbafc87 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -205,19 +205,38 @@ static ssize_t v9fs_file_write(struct file *filp, const char __user * data, size_t count, loff_t * offset) { - int ret; + int n, rsize, total = 0; struct p9_fid *fid; + struct p9_client *clnt; struct inode *inode = filp->f_path.dentry->d_inode; + int origin = *offset; P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count, (int)*offset); fid = filp->private_data; - ret = p9_client_write(fid, NULL, data, *offset, count); - if (ret > 0) { - invalidate_inode_pages2_range(inode->i_mapping, *offset, - *offset+ret); - *offset += ret; + clnt = fid->clnt; + + rsize = fid->iounit; + if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) + rsize = clnt->msize - P9_IOHDRSZ; + + do { + if (count < rsize) + rsize = count; + + n = p9_client_write(fid, NULL, data+total, *offset+total, + rsize); + if (n <= 0) + break; + count -= n; + total += n; + } while (count > 0); + + if (total > 0) { + invalidate_inode_pages2_range(inode->i_mapping, origin, + origin+total); + *offset += total; } if (*offset > inode->i_size) { @@ -225,7 +244,10 @@ v9fs_file_write(struct file *filp, const char __user * data, inode->i_blocks = (inode->i_size + 512 - 1) >> 9; } - return ret; + if (n < 0) + return n; + + return total; } static const struct file_operations v9fs_cached_file_operations = { From 06b55b464ee5b305aca75cb7d9424b184bf07f68 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 20:36:15 -0500 Subject: [PATCH 16/26] 9p: move dirread to fs layer Currently reading a directory is implemented in the client code. This function is not actually a wire operation, but a meta operation which calls read operations and processes the results. This patch moves this functionality to the fs layer and calls component wire operations instead of constructing their packets. This provides a cleaner separation and will help when we reorganize the client functions and protocol processing methods. Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_dir.c | 54 ++++++++++++++------- include/net/9p/client.h | 5 -- net/9p/client.c | 103 ---------------------------------------- 3 files changed, 38 insertions(+), 124 deletions(-) diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index e298fe194093..d7d0ac5a2ca3 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -69,32 +69,54 @@ static inline int dt_type(struct p9_stat *mistat) static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) { int over; + struct p9_stat st; + int err; struct p9_fid *fid; - struct v9fs_session_info *v9ses; - struct inode *inode; - struct p9_stat *st; + int buflen; + char *statbuf; + int n, i = 0; P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); - inode = filp->f_path.dentry->d_inode; - v9ses = v9fs_inode2v9ses(inode); fid = filp->private_data; - while ((st = p9_client_dirread(fid, filp->f_pos)) != NULL) { - if (IS_ERR(st)) - return PTR_ERR(st); - over = filldir(dirent, st->name.str, st->name.len, filp->f_pos, - v9fs_qid2ino(&st->qid), dt_type(st)); + buflen = fid->clnt->msize - P9_IOHDRSZ; + statbuf = kmalloc(buflen, GFP_KERNEL); + if (!statbuf) + return -ENOMEM; - if (over) + while (1) { + err = v9fs_file_readn(filp, statbuf, NULL, fid->rdir_fpos, + buflen); + if (err <= 0) break; - filp->f_pos += st->size; - kfree(st); - st = NULL; + n = err; + while (i < n) { + err = p9_deserialize_stat(statbuf + i, buflen-i, &st, + fid->clnt->dotu); + if (!err) { + err = -EIO; + goto free_and_exit; + } + + i += err; + fid->rdir_fpos += err; + + over = filldir(dirent, st.name.str, st.name.len, + filp->f_pos, v9fs_qid2ino(&st.qid), dt_type(&st)); + + filp->f_pos += st.size; + + if (over) { + err = 0; + goto free_and_exit; + } + } } - kfree(st); - return 0; +free_and_exit: + kfree(statbuf); + return err; } diff --git a/include/net/9p/client.h b/include/net/9p/client.h index bb8b0ede132d..eeb7d922816e 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -163,8 +163,6 @@ struct p9_client { * @uid: the numeric uid of the local user who owns this handle * @aux: transport specific information (unused?) * @rdir_fpos: tracks offset of file position when reading directory contents - * @rdir_pos: (unused?) - * @rdir_fcall: holds response of last directory read request * @flist: per-client-instance fid tracking * @dlist: per-dentry fid tracking * @@ -181,8 +179,6 @@ struct p9_fid { void *aux; int rdir_fpos; - int rdir_pos; - struct p9_fcall *rdir_fcall; struct list_head flist; struct list_head dlist; /* list of all fids attached to a dentry */ }; @@ -207,7 +203,6 @@ 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); 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_lookup(struct p9_client *, u16); void p9_client_cb(struct p9_client *c, struct p9_req_t *req); diff --git a/net/9p/client.c b/net/9p/client.c index d5ea042eabb0..90ee9efeede3 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -559,8 +559,6 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt) 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; @@ -586,7 +584,6 @@ static void p9_fid_destroy(struct p9_fid *fid) spin_lock(&clnt->lock); list_del(&fid->flist); spin_unlock(&clnt->lock); - kfree(fid->rdir_fcall); kfree(fid); } @@ -1261,103 +1258,3 @@ done: return err; } EXPORT_SYMBOL(p9_client_wstat); - -struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset) -{ - int err, n, m; - struct p9_fcall *tc, *rc; - struct p9_client *clnt; - struct p9_stat st, *ret; - - P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu\n", fid->fid, - (long long unsigned) offset); - err = 0; - tc = NULL; - rc = NULL; - ret = NULL; - clnt = fid->clnt; - - /* if the offset is below or above the current response, free it */ - if (offset < fid->rdir_fpos || (fid->rdir_fcall && - offset >= fid->rdir_fpos+fid->rdir_fcall->params.rread.count)) { - fid->rdir_pos = 0; - if (fid->rdir_fcall) - fid->rdir_fpos += fid->rdir_fcall->params.rread.count; - - kfree(fid->rdir_fcall); - fid->rdir_fcall = NULL; - if (offset < fid->rdir_fpos) - fid->rdir_fpos = 0; - } - - if (!fid->rdir_fcall) { - n = fid->iounit; - if (!n || n > clnt->msize-P9_IOHDRSZ) - n = clnt->msize - P9_IOHDRSZ; - - while (1) { - if (fid->rdir_fcall) { - fid->rdir_fpos += - fid->rdir_fcall->params.rread.count; - kfree(fid->rdir_fcall); - fid->rdir_fcall = NULL; - } - - tc = p9_create_tread(fid->fid, fid->rdir_fpos, n); - 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; - if (n == 0) - goto done; - - fid->rdir_fcall = rc; - rc = NULL; - if (offset >= fid->rdir_fpos && - offset < fid->rdir_fpos+n) - break; - } - - fid->rdir_pos = 0; - } - - m = offset - fid->rdir_fpos; - if (m < 0) - goto done; - - n = p9_deserialize_stat(fid->rdir_fcall->params.rread.data + m, - fid->rdir_fcall->params.rread.count - m, &st, clnt->dotu); - - if (!n) { - err = -EIO; - goto error; - } - - fid->rdir_pos += n; - st.size = n; - ret = p9_clone_stat(&st, clnt->dotu); - if (IS_ERR(ret)) { - err = PTR_ERR(ret); - ret = NULL; - goto error; - } - -done: - kfree(tc); - kfree(rc); - return ret; - -error: - kfree(tc); - kfree(rc); - kfree(ret); - return ERR_PTR(err); -} -EXPORT_SYMBOL(p9_client_dirread); From 6936bf60d2c407449c09e3f28ec0301e1f937106 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 20:36:14 -0500 Subject: [PATCH 17/26] 9p: encapsulate version function Alsmot all 9P client wire functions have their own (set of) functions. Tversion is an exception as its encapsulated into the client_create code. This patch moves the protocol specifics of this to a function to match the rest of the code. Signed-off-by: Eric Van Hensbergen --- net/9p/client.c | 74 +++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/net/9p/client.c b/net/9p/client.c index 90ee9efeede3..a9982df00a3a 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -587,16 +587,56 @@ static void p9_fid_destroy(struct p9_fid *fid) kfree(fid); } -struct p9_client *p9_client_create(const char *dev_name, char *options) +static int p9_client_version(struct p9_client *clnt) { - int err, n; - struct p9_client *clnt; + int err = 0; struct p9_fcall *tc, *rc; struct p9_str *version; + 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; + } + + err = p9_client_rpc(clnt, tc, &rc); + if (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; + else { + err = -EREMOTEIO; + goto error; + } + + if (rc->params.rversion.msize < clnt->msize) + clnt->msize = rc->params.rversion.msize; + +error: + kfree(tc); + kfree(rc); + + return err; +} +EXPORT_SYMBOL(p9_client_auth); + +struct p9_client *p9_client_create(const char *dev_name, char *options) +{ + int err; + struct p9_client *clnt; + + err = 0; clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL); if (!clnt) return ERR_PTR(-ENOMEM); @@ -628,7 +668,6 @@ struct p9_client *p9_client_create(const char *dev_name, char *options) P9_DPRINTK(P9_DEBUG_9P, "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); if (err) goto error; @@ -636,38 +675,13 @@ struct p9_client *p9_client_create(const char *dev_name, char *options) if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize) clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ; - tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000"); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto error; - } - - err = p9_client_rpc(clnt, tc, &rc); + err = p9_client_version(clnt); if (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; - else { - err = -EREMOTEIO; - goto error; - } - - n = rc->params.rversion.msize; - if (n < clnt->msize) - clnt->msize = n; - - kfree(tc); - kfree(rc); return clnt; error: - kfree(tc); - kfree(rc); p9_client_destroy(clnt); return ERR_PTR(err); } From ace51c4dd2f968f427c4627023759ae7e3786cba Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 13 Oct 2008 20:40:27 -0500 Subject: [PATCH 18/26] 9p: add new protocol support code This adds a new protocol processing support code based on Anthony Liguori's 9p library code. This code performs protocol marshalling/unmarshalling using printf like strings to represent protocol elements. It is my intent to use them to replace the current functions in conv.c as well as the p9_create_* functions. This should make the client implementation much more clear, and also make it much easier to add new protocol extensions by limiting the number of places in which changes need to be made. Signed-off-by: Eric Van Hensbergen --- include/net/9p/9p.h | 8 +- net/9p/Makefile | 1 + net/9p/protocol.c | 457 ++++++++++++++++++++++++++++++++++++++++++++ net/9p/protocol.h | 31 +++ 4 files changed, 496 insertions(+), 1 deletion(-) create mode 100644 net/9p/protocol.c create mode 100644 net/9p/protocol.h diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index fb163e2e0de6..f9e25268b70f 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h @@ -509,6 +509,8 @@ struct p9_rwstat { * @size: prefixed length of the structure * @id: protocol operating identifier of type &p9_msg_t * @tag: transaction id of the request + * @offset: used by marshalling routines to track currentposition in buffer + * @capacity: used by marshalling routines to track total capacity * @sdata: payload * @params: per-operation parameters * @@ -523,7 +525,11 @@ struct p9_fcall { u32 size; u8 id; u16 tag; - void *sdata; + + size_t offset; + size_t capacity; + + uint8_t *sdata; union { struct p9_tversion tversion; diff --git a/net/9p/Makefile b/net/9p/Makefile index 519219480db1..84c23499a293 100644 --- a/net/9p/Makefile +++ b/net/9p/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_NET_9P_VIRTIO) += 9pnet_virtio.o error.o \ fcprint.o \ util.o \ + protocol.o \ trans_fd.o \ 9pnet_virtio-objs := \ diff --git a/net/9p/protocol.c b/net/9p/protocol.c new file mode 100644 index 000000000000..43e98220e9a4 --- /dev/null +++ b/net/9p/protocol.c @@ -0,0 +1,457 @@ +/* + * net/9p/protocol.c + * + * 9P Protocol Support Code + * + * Copyright (C) 2008 by Eric Van Hensbergen + * + * Base on code from Anthony Liguori + * Copyright (C) 2008 by IBM, Corp. + * + * 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 "protocol.h" + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef offset_of +#define offset_of(type, memb) \ + ((unsigned long)(&((type *)0)->memb)) +#endif +#ifndef container_of +#define container_of(obj, type, memb) \ + ((type *)(((char *)obj) - offset_of(type, memb))) +#endif + +static int +p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...); + +void p9stat_free(struct p9_wstat *stbuf) +{ + kfree(stbuf->name); + kfree(stbuf->uid); + kfree(stbuf->gid); + kfree(stbuf->muid); + kfree(stbuf->extension); +} +EXPORT_SYMBOL(p9stat_free); + +static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size) +{ + size_t len = MIN(pdu->size - pdu->offset, size); + memcpy(data, &pdu->sdata[pdu->offset], len); + pdu->offset += len; + return size - len; +} + +static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size) +{ + size_t len = MIN(pdu->capacity - pdu->size, size); + memcpy(&pdu->sdata[pdu->size], data, len); + pdu->size += len; + return size - len; +} + +/* + b - int8_t + w - int16_t + d - int32_t + q - int64_t + s - string + S - stat + Q - qid + D - data blob (int32_t size followed by void *, results are not freed) + T - array of strings (int16_t count, followed by strings) + R - array of qids (int16_t count, followed by qids) + ? - if optional = 1, continue parsing +*/ + +static int +p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) +{ + const char *ptr; + int errcode = 0; + + for (ptr = fmt; *ptr; ptr++) { + switch (*ptr) { + case 'b':{ + int8_t *val = va_arg(ap, int8_t *); + if (pdu_read(pdu, val, sizeof(*val))) { + errcode = -EFAULT; + break; + } + } + break; + case 'w':{ + int16_t *val = va_arg(ap, int16_t *); + if (pdu_read(pdu, val, sizeof(*val))) { + errcode = -EFAULT; + break; + } + *val = cpu_to_le16(*val); + } + break; + case 'd':{ + int32_t *val = va_arg(ap, int32_t *); + if (pdu_read(pdu, val, sizeof(*val))) { + errcode = -EFAULT; + break; + } + *val = cpu_to_le32(*val); + } + break; + case 'q':{ + int64_t *val = va_arg(ap, int64_t *); + if (pdu_read(pdu, val, sizeof(*val))) { + errcode = -EFAULT; + break; + } + *val = cpu_to_le64(*val); + } + break; + case 's':{ + char **ptr = va_arg(ap, char **); + int16_t len; + int size; + + errcode = p9pdu_readf(pdu, optional, "w", &len); + if (errcode) + break; + + size = MAX(len, 0); + + *ptr = kmalloc(size + 1, GFP_KERNEL); + if (*ptr == NULL) { + errcode = -EFAULT; + break; + } + if (pdu_read(pdu, *ptr, size)) { + errcode = -EFAULT; + kfree(*ptr); + *ptr = NULL; + } else + (*ptr)[size] = 0; + } + break; + case 'Q':{ + struct p9_qid *qid = + va_arg(ap, struct p9_qid *); + + errcode = p9pdu_readf(pdu, optional, "bdq", + &qid->type, &qid->version, + &qid->path); + } + break; + case 'S':{ + struct p9_wstat *stbuf = + va_arg(ap, struct p9_wstat *); + + stbuf->extension = NULL; + stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = + -1; + + errcode = + p9pdu_readf(pdu, optional, + "wwdQdddqssss?sddd", + &stbuf->size, &stbuf->type, + &stbuf->dev, &stbuf->qid, + &stbuf->mode, &stbuf->atime, + &stbuf->mtime, &stbuf->length, + &stbuf->name, &stbuf->uid, + &stbuf->gid, &stbuf->muid, + &stbuf->extension, + &stbuf->n_uid, &stbuf->n_gid, + &stbuf->n_muid); + if (errcode) + p9stat_free(stbuf); + } + break; + case 'D':{ + int32_t *count = va_arg(ap, int32_t *); + void **data = va_arg(ap, void **); + + errcode = + p9pdu_readf(pdu, optional, "d", count); + if (!errcode) { + *count = + MIN(*count, + pdu->size - pdu->offset); + *data = &pdu->sdata[pdu->offset]; + } + } + break; + case 'T':{ + int16_t *nwname = va_arg(ap, int16_t *); + char ***wnames = va_arg(ap, char ***); + + errcode = + p9pdu_readf(pdu, optional, "w", nwname); + if (!errcode) { + *wnames = + kmalloc(sizeof(char *) * *nwname, + GFP_KERNEL); + if (!*wnames) + errcode = -ENOMEM; + } + + if (!errcode) { + int i; + + for (i = 0; i < *nwname; i++) { + errcode = + p9pdu_readf(pdu, optional, + "s", + &(*wnames)[i]); + if (errcode) + break; + } + } + + if (errcode) { + if (*wnames) { + int i; + + for (i = 0; i < *nwname; i++) + kfree((*wnames)[i]); + } + kfree(*wnames); + *wnames = NULL; + } + } + break; + case 'R':{ + int16_t *nwqid = va_arg(ap, int16_t *); + struct p9_qid **wqids = + va_arg(ap, struct p9_qid **); + + *wqids = NULL; + + errcode = + p9pdu_readf(pdu, optional, "w", nwqid); + if (!errcode) { + *wqids = + kmalloc(*nwqid * + sizeof(struct p9_qid), + GFP_KERNEL); + if (*wqids == NULL) + errcode = -ENOMEM; + } + + if (!errcode) { + int i; + + for (i = 0; i < *nwqid; i++) { + errcode = + p9pdu_readf(pdu, optional, + "Q", + &(*wqids)[i]); + if (errcode) + break; + } + } + + if (errcode) { + kfree(*wqids); + *wqids = NULL; + } + } + break; + case '?': + if (!optional) + return 0; + break; + default: + BUG(); + break; + } + + if (errcode) + break; + } + + return errcode; +} + +int +p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) +{ + const char *ptr; + int errcode = 0; + + for (ptr = fmt; *ptr; ptr++) { + switch (*ptr) { + case 'b':{ + int8_t val = va_arg(ap, int); + if (pdu_write(pdu, &val, sizeof(val))) + errcode = -EFAULT; + } + break; + case 'w':{ + int16_t val = va_arg(ap, int); + if (pdu_write(pdu, &val, sizeof(val))) + errcode = -EFAULT; + } + break; + case 'd':{ + int32_t val = va_arg(ap, int32_t); + if (pdu_write(pdu, &val, sizeof(val))) + errcode = -EFAULT; + } + break; + case 'q':{ + int64_t val = va_arg(ap, int64_t); + if (pdu_write(pdu, &val, sizeof(val))) + errcode = -EFAULT; + } + break; + case 's':{ + const char *ptr = va_arg(ap, const char *); + int16_t len = 0; + + if (ptr) + len = MIN(strlen(ptr), USHORT_MAX); + + errcode = p9pdu_writef(pdu, optional, "w", len); + if (!errcode && pdu_write(pdu, ptr, len)) + errcode = -EFAULT; + } + break; + case 'Q':{ + const struct p9_qid *qid = + va_arg(ap, const struct p9_qid *); + errcode = + p9pdu_writef(pdu, optional, "bdq", + qid->type, qid->version, + qid->path); + } break; + case 'S':{ + const struct p9_wstat *stbuf = + va_arg(ap, const struct p9_wstat *); + errcode = + p9pdu_writef(pdu, optional, + "wwdQdddqssss?sddd", + stbuf->size, stbuf->type, + stbuf->dev, stbuf->qid, + stbuf->mode, stbuf->atime, + stbuf->mtime, stbuf->length, + stbuf->name, stbuf->uid, + stbuf->gid, stbuf->muid, + stbuf->extension, stbuf->n_uid, + stbuf->n_gid, stbuf->n_muid); + } break; + case 'D':{ + int32_t count = va_arg(ap, int32_t); + const void *data = va_arg(ap, const void *); + + errcode = + p9pdu_writef(pdu, optional, "d", count); + if (!errcode && pdu_write(pdu, data, count)) + errcode = -EFAULT; + } + break; + case 'T':{ + int16_t nwname = va_arg(ap, int); + const char **wnames = va_arg(ap, const char **); + + errcode = + p9pdu_writef(pdu, optional, "w", nwname); + if (!errcode) { + int i; + + for (i = 0; i < nwname; i++) { + errcode = + p9pdu_writef(pdu, optional, + "s", + wnames[i]); + if (errcode) + break; + } + } + } + break; + case 'R':{ + int16_t nwqid = va_arg(ap, int); + struct p9_qid *wqids = + va_arg(ap, struct p9_qid *); + + errcode = + p9pdu_writef(pdu, optional, "w", nwqid); + if (!errcode) { + int i; + + for (i = 0; i < nwqid; i++) { + errcode = + p9pdu_writef(pdu, optional, + "Q", + &wqids[i]); + if (errcode) + break; + } + } + } + break; + case '?': + if (!optional) + return 0; + break; + default: + BUG(); + break; + } + + if (errcode) + break; + } + + return errcode; +} + +int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = p9pdu_vreadf(pdu, optional, fmt, ap); + va_end(ap); + + return ret; +} + +static int +p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = p9pdu_vwritef(pdu, optional, fmt, ap); + va_end(ap); + + return ret; +} diff --git a/net/9p/protocol.h b/net/9p/protocol.h new file mode 100644 index 000000000000..596ee10d506f --- /dev/null +++ b/net/9p/protocol.h @@ -0,0 +1,31 @@ +/* + * net/9p/protocol.h + * + * 9P Protocol Support Code + * + * Copyright (C) 2008 by Eric Van Hensbergen + * + * Base on code from Anthony Liguori + * Copyright (C) 2008 by IBM, Corp. + * + * 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 + * + */ + +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, ...); From 51d71f9f7a639c8a39401de1ec5ce9b0b6476c99 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Thu, 16 Oct 2008 08:29:31 -0500 Subject: [PATCH 19/26] 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 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); From cb198131b0e7aba755ac164744536d461e86ab82 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Thu, 16 Oct 2008 08:29:31 -0500 Subject: [PATCH 20/26] 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(-) 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); From 51a87c552dfd428e304c865e24ecbe091556f226 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Thu, 16 Oct 2008 08:30:07 -0500 Subject: [PATCH 21/26] 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 | 943 ++++++++++++++++++++-------------------- net/9p/protocol.c | 85 +++- net/9p/protocol.h | 5 +- net/9p/trans_fd.c | 62 ++- net/9p/util.c | 4 + 12 files changed, 617 insertions(+), 550 deletions(-) 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); @@ -365,28 +359,164 @@ void p9_client_cb(struct p9_client *c, struct p9_req_t *req) 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 + * 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 */ -static int -p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) +int +p9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type, int16_t *tag, + int rewind) { - int tag, err, size; - char *rdata; + 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 + * @type: type of request + * @fmt: protocol format string (see protocol.c) + * + * Returns request structure (which client must free using p9_free_req) + */ + +static struct p9_req_t * +p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) +{ + 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; + 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); - tc = p9_create_tversion(clnt->msize, - clnt->dotu ? "9P2000.u" : "9P2000"); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; + err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version); + if (err) { + P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); goto error; } - err = p9_client_rpc(clnt, tc, &rc); - if (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 = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr); + if (err) + goto free_and_error; + + P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); + + if (data) { + memmove(data, dataptr, count); + data += count; + } + + if (udata) { + err = copy_to_user(udata, dataptr, count); + if (err) { + err = -EFAULT; + goto free_and_error; } + } - err = p9_client_rpc(clnt, tc, &rc); - if (err) - goto error; - - n = rc->params.rread.count; - if (n > count) - n = count; - - if (data) { - memmove(data, rc->params.rread.data, n); - data += n; - } - - if (udata) { - err = copy_to_user(udata, rc->params.rread.data, n); - if (err) { - err = -EFAULT; - goto error; - } - udata += n; - } - - 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 (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; + } - 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 = p9pdu_readf(req->rc, clnt->dotu, "d", &count); + if (err) + goto free_and_error; + P9_DPRINTK(P9_DEBUG_9P, "<<< RWRITE count %d\n", count); - 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; - - offset += n; - total += n; - kfree(tc); - tc = NULL; - kfree(rc); - rc = NULL; - } while (count > 0); - - 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; + int err; + struct p9_client *clnt; + struct p9_wstat *ret = kmalloc(sizeof(struct p9_wstat), GFP_KERNEL); + struct p9_req_t *req; + u16 ignored; - n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len + - st->muid.len; + P9_DPRINTK(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid); - 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; - 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); From 02da398b950c5d079c20afaa23f322383e96070a Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Thu, 16 Oct 2008 08:29:30 -0500 Subject: [PATCH 22/26] 9p: eliminate depricated conv functions Remove depricated conv functions which have been replaced with new protocol routines. This patch also reworks the one instance of the file-system code which directly calls conversion routines (to accomplish unpacking dirreads). Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_dir.c | 20 +- include/net/9p/9p.h | 107 +--- include/net/9p/client.h | 2 + net/9p/Makefile | 1 - net/9p/conv.c | 1054 --------------------------------------- net/9p/protocol.c | 13 + 6 files changed, 37 insertions(+), 1160 deletions(-) delete mode 100644 net/9p/conv.c diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 276aed625929..873cd31baa47 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -45,7 +45,7 @@ * */ -static inline int dt_type(struct p9_stat *mistat) +static inline int dt_type(struct p9_wstat *mistat) { unsigned long perm = mistat->mode; int rettype = DT_REG; @@ -69,7 +69,7 @@ static inline int dt_type(struct p9_stat *mistat) static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) { int over; - struct p9_stat st; + struct p9_wstat st; int err; struct p9_fid *fid; int buflen; @@ -92,20 +92,24 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) n = err; while (i < n) { - err = p9_deserialize_stat(statbuf + i, buflen-i, &st, + err = p9stat_read(statbuf + i, buflen-i, &st, fid->clnt->dotu); - if (!err) { + if (err) { + P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); err = -EIO; + p9stat_free(&st); goto free_and_exit; } - i += err; - fid->rdir_fpos += err; + i += st.size+2; + fid->rdir_fpos += st.size+2; - over = filldir(dirent, st.name.str, st.name.len, + over = filldir(dirent, st.name, strlen(st.name), filp->f_pos, v9fs_qid2ino(&st.qid), dt_type(&st)); - filp->f_pos += st.size; + filp->f_pos += st.size+2; + + p9stat_free(&st); if (over) { err = 0; diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index 56c15aee6e61..cb5bc731e885 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h @@ -61,21 +61,18 @@ extern unsigned int p9_debug_level; #define P9_DPRINTK(level, format, arg...) \ do { \ - 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); \ + if ((p9_debug_level & level) == level) {\ + if (level == P9_DEBUG_9P) \ + printk(KERN_NOTICE "(%8.8d) " \ + format , task_pid_nr(current) , ## arg); \ + else \ + printk(KERN_NOTICE "-- %s (%d): " \ + format , __func__, task_pid_nr(current) , ## arg); \ + } \ } while (0) -#define PRINT_FCALL_ERROR(s, fcall) P9_DPRINTK(P9_DEBUG_ERROR, \ - "%s: %.*s\n", s, fcall?fcall->params.rerror.error.len:0, \ - fcall?fcall->params.rerror.error.str:""); - #else #define P9_DPRINTK(level, format, arg...) do { } while (0) -#define PRINT_FCALL_ERROR(s, fcall) do { } while (0) #endif #define P9_EPRINTK(level, format, arg...) \ @@ -330,33 +327,6 @@ struct p9_qid { * See Also: http://plan9.bell-labs.com/magic/man2html/2/stat */ -struct p9_stat { - u16 size; - u16 type; - u32 dev; - struct p9_qid qid; - u32 mode; - u32 atime; - u32 mtime; - u64 length; - struct p9_str name; - struct p9_str uid; - struct p9_str gid; - struct p9_str muid; - struct p9_str extension; /* 9p2000.u extensions */ - u32 n_uid; /* 9p2000.u extensions */ - u32 n_gid; /* 9p2000.u extensions */ - u32 n_muid; /* 9p2000.u extensions */ -}; - -/* - * file metadata (stat) structure used to create Twstat message - * The is identical to &p9_stat, but the strings don't point to - * the same memory block and should be freed separately - * - * See Also: http://plan9.bell-labs.com/magic/man2html/2/stat - */ - struct p9_wstat { u16 size; u16 type; @@ -498,12 +468,12 @@ struct p9_tstat { }; struct p9_rstat { - struct p9_stat stat; + struct p9_wstat stat; }; struct p9_twstat { u32 fid; - struct p9_stat stat; + struct p9_wstat stat; }; struct p9_rwstat { @@ -517,7 +487,6 @@ struct p9_rwstat { * @offset: used by marshalling routines to track currentposition in buffer * @capacity: used by marshalling routines to track total capacity * @sdata: payload - * @params: per-operation parameters * * &p9_fcall represents the structure for all 9P RPC * transactions. Requests are packaged into fcalls, and reponses @@ -535,66 +504,10 @@ struct p9_fcall { size_t capacity; uint8_t *sdata; - - union { - struct p9_tversion tversion; - struct p9_rversion rversion; - struct p9_tauth tauth; - struct p9_rauth rauth; - struct p9_rerror rerror; - struct p9_tflush tflush; - struct p9_rflush rflush; - struct p9_tattach tattach; - struct p9_rattach rattach; - struct p9_twalk twalk; - struct p9_rwalk rwalk; - struct p9_topen topen; - struct p9_ropen ropen; - struct p9_tcreate tcreate; - struct p9_rcreate rcreate; - struct p9_tread tread; - struct p9_rread rread; - struct p9_twrite twrite; - struct p9_rwrite rwrite; - struct p9_tclunk tclunk; - struct p9_rclunk rclunk; - struct p9_tremove tremove; - struct p9_rremove rremove; - struct p9_tstat tstat; - struct p9_rstat rstat; - struct p9_twstat twstat; - struct p9_rwstat rwstat; - } params; }; struct p9_idpool; -int p9_deserialize_stat(void *buf, u32 buflen, struct p9_stat *stat, - int dotu); -int p9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *fc, int dotu); -void p9_set_tag(struct p9_fcall *fc, u16 tag); -struct p9_fcall *p9_create_tversion(u32 msize, char *version); -struct p9_fcall *p9_create_tattach(u32 fid, u32 afid, char *uname, - char *aname, u32 n_uname, int dotu); -struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname, - u32 n_uname, int dotu); -struct p9_fcall *p9_create_tflush(u16 oldtag); -struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname, - char **wnames); -struct p9_fcall *p9_create_topen(u32 fid, u8 mode); -struct p9_fcall *p9_create_tcreate(u32 fid, char *name, u32 perm, u8 mode, - char *extension, int dotu); -struct p9_fcall *p9_create_tread(u32 fid, u64 offset, u32 count); -struct p9_fcall *p9_create_twrite(u32 fid, u64 offset, u32 count, - const char *data); -struct p9_fcall *p9_create_twrite_u(u32 fid, u64 offset, u32 count, - const char __user *data); -struct p9_fcall *p9_create_tclunk(u32 fid); -struct p9_fcall *p9_create_tremove(u32 fid); -struct p9_fcall *p9_create_tstat(u32 fid); -struct p9_fcall *p9_create_twstat(u32 fid, struct p9_wstat *wstat, - int dotu); - int p9_errstr2errno(char *errstr, int len); struct p9_idpool *p9_idpool_create(void); diff --git a/include/net/9p/client.h b/include/net/9p/client.h index 1e49b4d1030b..1f17f3d93727 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -206,6 +206,8 @@ 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); +int p9stat_read(char *, int, struct p9_wstat *, int); void p9stat_free(struct p9_wstat *); + #endif /* NET_9P_CLIENT_H */ diff --git a/net/9p/Makefile b/net/9p/Makefile index c3302d88b808..1041b7bd12e2 100644 --- a/net/9p/Makefile +++ b/net/9p/Makefile @@ -4,7 +4,6 @@ obj-$(CONFIG_NET_9P_VIRTIO) += 9pnet_virtio.o 9pnet-objs := \ mod.o \ client.o \ - conv.o \ error.o \ util.o \ protocol.o \ diff --git a/net/9p/conv.c b/net/9p/conv.c deleted file mode 100644 index 5ad3a3bd73b2..000000000000 --- a/net/9p/conv.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* - * net/9p/conv.c - * - * 9P protocol conversion functions - * - * Copyright (C) 2004, 2005 by Latchesar Ionkov - * Copyright (C) 2004 by Eric Van Hensbergen - * Copyright (C) 2002 by Ron Minnich - * - * 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 -#include -#include - -/* - * Buffer to help with string parsing - */ -struct cbuf { - unsigned char *sp; - unsigned char *p; - unsigned char *ep; -}; - -static inline void buf_init(struct cbuf *buf, void *data, int datalen) -{ - buf->sp = buf->p = data; - buf->ep = data + datalen; -} - -static inline int buf_check_overflow(struct cbuf *buf) -{ - return buf->p > buf->ep; -} - -static int buf_check_size(struct cbuf *buf, int len) -{ - if (buf->p + len > buf->ep) { - if (buf->p < buf->ep) { - P9_EPRINTK(KERN_ERR, - "buffer overflow: want %d has %d\n", len, - (int)(buf->ep - buf->p)); - dump_stack(); - buf->p = buf->ep + 1; - } - - return 0; - } - - return 1; -} - -static void *buf_alloc(struct cbuf *buf, int len) -{ - void *ret = NULL; - - if (buf_check_size(buf, len)) { - ret = buf->p; - buf->p += len; - } - - return ret; -} - -static void buf_put_int8(struct cbuf *buf, u8 val) -{ - if (buf_check_size(buf, 1)) { - buf->p[0] = val; - buf->p++; - } -} - -static void buf_put_int16(struct cbuf *buf, u16 val) -{ - if (buf_check_size(buf, 2)) { - *(__le16 *) buf->p = cpu_to_le16(val); - buf->p += 2; - } -} - -static void buf_put_int32(struct cbuf *buf, u32 val) -{ - if (buf_check_size(buf, 4)) { - *(__le32 *)buf->p = cpu_to_le32(val); - buf->p += 4; - } -} - -static void buf_put_int64(struct cbuf *buf, u64 val) -{ - if (buf_check_size(buf, 8)) { - *(__le64 *)buf->p = cpu_to_le64(val); - buf->p += 8; - } -} - -static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen) -{ - char *ret; - - ret = NULL; - if (buf_check_size(buf, slen + 2)) { - buf_put_int16(buf, slen); - ret = buf->p; - memcpy(buf->p, s, slen); - buf->p += slen; - } - - return ret; -} - -static u8 buf_get_int8(struct cbuf *buf) -{ - u8 ret = 0; - - if (buf_check_size(buf, 1)) { - ret = buf->p[0]; - buf->p++; - } - - return ret; -} - -static u16 buf_get_int16(struct cbuf *buf) -{ - u16 ret = 0; - - if (buf_check_size(buf, 2)) { - ret = le16_to_cpu(*(__le16 *)buf->p); - buf->p += 2; - } - - return ret; -} - -static u32 buf_get_int32(struct cbuf *buf) -{ - u32 ret = 0; - - if (buf_check_size(buf, 4)) { - ret = le32_to_cpu(*(__le32 *)buf->p); - buf->p += 4; - } - - return ret; -} - -static u64 buf_get_int64(struct cbuf *buf) -{ - u64 ret = 0; - - if (buf_check_size(buf, 8)) { - ret = le64_to_cpu(*(__le64 *)buf->p); - buf->p += 8; - } - - return ret; -} - -static void buf_get_str(struct cbuf *buf, struct p9_str *vstr) -{ - vstr->len = buf_get_int16(buf); - if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) { - vstr->str = buf->p; - buf->p += vstr->len; - } else { - vstr->len = 0; - vstr->str = NULL; - } -} - -static void buf_get_qid(struct cbuf *bufp, struct p9_qid *qid) -{ - qid->type = buf_get_int8(bufp); - qid->version = buf_get_int32(bufp); - qid->path = buf_get_int64(bufp); -} - -/** - * p9_size_wstat - calculate the size of a variable length stat struct - * @wstat: metadata (stat) structure - * @dotu: non-zero if 9P2000.u - * - */ - -static int p9_size_wstat(struct p9_wstat *wstat, int dotu) -{ - int size = 0; - - if (wstat == NULL) { - P9_EPRINTK(KERN_ERR, "p9_size_stat: got a NULL stat pointer\n"); - return 0; - } - - size = /* 2 + *//* size[2] */ - 2 + /* type[2] */ - 4 + /* dev[4] */ - 1 + /* qid.type[1] */ - 4 + /* qid.vers[4] */ - 8 + /* qid.path[8] */ - 4 + /* mode[4] */ - 4 + /* atime[4] */ - 4 + /* mtime[4] */ - 8 + /* length[8] */ - 8; /* minimum sum of string lengths */ - - if (wstat->name) - size += strlen(wstat->name); - if (wstat->uid) - size += strlen(wstat->uid); - if (wstat->gid) - size += strlen(wstat->gid); - if (wstat->muid) - size += strlen(wstat->muid); - - if (dotu) { - size += 4 + /* n_uid[4] */ - 4 + /* n_gid[4] */ - 4 + /* n_muid[4] */ - 2; /* string length of extension[4] */ - if (wstat->extension) - size += strlen(wstat->extension); - } - - return size; -} - -/** - * buf_get_stat - safely decode a recieved metadata (stat) structure - * @bufp: buffer to deserialize - * @stat: metadata (stat) structure - * @dotu: non-zero if 9P2000.u - * - */ - -static void -buf_get_stat(struct cbuf *bufp, struct p9_stat *stat, int dotu) -{ - stat->size = buf_get_int16(bufp); - stat->type = buf_get_int16(bufp); - stat->dev = buf_get_int32(bufp); - stat->qid.type = buf_get_int8(bufp); - stat->qid.version = buf_get_int32(bufp); - stat->qid.path = buf_get_int64(bufp); - stat->mode = buf_get_int32(bufp); - stat->atime = buf_get_int32(bufp); - stat->mtime = buf_get_int32(bufp); - stat->length = buf_get_int64(bufp); - buf_get_str(bufp, &stat->name); - buf_get_str(bufp, &stat->uid); - buf_get_str(bufp, &stat->gid); - buf_get_str(bufp, &stat->muid); - - if (dotu) { - buf_get_str(bufp, &stat->extension); - stat->n_uid = buf_get_int32(bufp); - stat->n_gid = buf_get_int32(bufp); - stat->n_muid = buf_get_int32(bufp); - } -} - -/** - * p9_deserialize_stat - decode a received metadata structure - * @buf: buffer to deserialize - * @buflen: length of received buffer - * @stat: metadata structure to decode into - * @dotu: non-zero if 9P2000.u - * - * Note: stat will point to the buf region. - */ - -int -p9_deserialize_stat(void *buf, u32 buflen, struct p9_stat *stat, - int dotu) -{ - struct cbuf buffer; - struct cbuf *bufp = &buffer; - unsigned char *p; - - buf_init(bufp, buf, buflen); - p = bufp->p; - buf_get_stat(bufp, stat, dotu); - - if (buf_check_overflow(bufp)) - return 0; - else - return bufp->p - p; -} -EXPORT_SYMBOL(p9_deserialize_stat); - -/** - * deserialize_fcall - unmarshal a response - * @buf: recieved buffer - * @buflen: length of received buffer - * @rcall: fcall structure to populate - * @rcalllen: length of fcall structure to populate - * @dotu: non-zero if 9P2000.u - * - */ - -int -p9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *rcall, - int dotu) -{ - - struct cbuf buffer; - struct cbuf *bufp = &buffer; - int i = 0; - - buf_init(bufp, buf, buflen); - - rcall->size = buf_get_int32(bufp); - rcall->id = buf_get_int8(bufp); - rcall->tag = buf_get_int16(bufp); - - P9_DPRINTK(P9_DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, - rcall->id, rcall->tag); - - switch (rcall->id) { - default: - P9_EPRINTK(KERN_ERR, "unknown message type: %d\n", rcall->id); - return -EPROTO; - case P9_RVERSION: - rcall->params.rversion.msize = buf_get_int32(bufp); - buf_get_str(bufp, &rcall->params.rversion.version); - break; - case P9_RFLUSH: - break; - case P9_RATTACH: - rcall->params.rattach.qid.type = buf_get_int8(bufp); - rcall->params.rattach.qid.version = buf_get_int32(bufp); - rcall->params.rattach.qid.path = buf_get_int64(bufp); - break; - case P9_RWALK: - rcall->params.rwalk.nwqid = buf_get_int16(bufp); - if (rcall->params.rwalk.nwqid > P9_MAXWELEM) { - P9_EPRINTK(KERN_ERR, - "Rwalk with more than %d qids: %d\n", - P9_MAXWELEM, rcall->params.rwalk.nwqid); - return -EPROTO; - } - - for (i = 0; i < rcall->params.rwalk.nwqid; i++) - buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]); - break; - case P9_ROPEN: - buf_get_qid(bufp, &rcall->params.ropen.qid); - rcall->params.ropen.iounit = buf_get_int32(bufp); - break; - case P9_RCREATE: - buf_get_qid(bufp, &rcall->params.rcreate.qid); - rcall->params.rcreate.iounit = buf_get_int32(bufp); - break; - case P9_RREAD: - rcall->params.rread.count = buf_get_int32(bufp); - rcall->params.rread.data = bufp->p; - buf_check_size(bufp, rcall->params.rread.count); - break; - case P9_RWRITE: - rcall->params.rwrite.count = buf_get_int32(bufp); - break; - case P9_RCLUNK: - break; - case P9_RREMOVE: - break; - case P9_RSTAT: - buf_get_int16(bufp); - buf_get_stat(bufp, &rcall->params.rstat.stat, dotu); - break; - case P9_RWSTAT: - break; - case P9_RERROR: - buf_get_str(bufp, &rcall->params.rerror.error); - if (dotu) - rcall->params.rerror.errno = buf_get_int16(bufp); - break; - } - - if (buf_check_overflow(bufp)) { - P9_DPRINTK(P9_DEBUG_ERROR, "buffer overflow\n"); - return -EIO; - } - - return bufp->p - bufp->sp; -} -EXPORT_SYMBOL(p9_deserialize_fcall); - -static inline void p9_put_int8(struct cbuf *bufp, u8 val, u8 * p) -{ - *p = val; - buf_put_int8(bufp, val); -} - -static inline void p9_put_int16(struct cbuf *bufp, u16 val, u16 * p) -{ - *p = val; - buf_put_int16(bufp, val); -} - -static inline void p9_put_int32(struct cbuf *bufp, u32 val, u32 * p) -{ - *p = val; - buf_put_int32(bufp, val); -} - -static inline void p9_put_int64(struct cbuf *bufp, u64 val, u64 * p) -{ - *p = val; - buf_put_int64(bufp, val); -} - -static void -p9_put_str(struct cbuf *bufp, char *data, struct p9_str *str) -{ - int len; - char *s; - - if (data) - len = strlen(data); - else - len = 0; - - s = buf_put_stringn(bufp, data, len); - if (str) { - str->len = len; - str->str = s; - } -} - -static int -p9_put_data(struct cbuf *bufp, const char *data, int count, - unsigned char **pdata) -{ - *pdata = buf_alloc(bufp, count); - if (*pdata == NULL) - return -ENOMEM; - memmove(*pdata, data, count); - return 0; -} - -static int -p9_put_user_data(struct cbuf *bufp, const char __user *data, int count, - unsigned char **pdata) -{ - *pdata = buf_alloc(bufp, count); - if (*pdata == NULL) - return -ENOMEM; - return copy_from_user(*pdata, data, count); -} - -static void -p9_put_wstat(struct cbuf *bufp, struct p9_wstat *wstat, - struct p9_stat *stat, int statsz, int dotu) -{ - p9_put_int16(bufp, statsz, &stat->size); - p9_put_int16(bufp, wstat->type, &stat->type); - p9_put_int32(bufp, wstat->dev, &stat->dev); - p9_put_int8(bufp, wstat->qid.type, &stat->qid.type); - p9_put_int32(bufp, wstat->qid.version, &stat->qid.version); - p9_put_int64(bufp, wstat->qid.path, &stat->qid.path); - p9_put_int32(bufp, wstat->mode, &stat->mode); - p9_put_int32(bufp, wstat->atime, &stat->atime); - p9_put_int32(bufp, wstat->mtime, &stat->mtime); - p9_put_int64(bufp, wstat->length, &stat->length); - - p9_put_str(bufp, wstat->name, &stat->name); - p9_put_str(bufp, wstat->uid, &stat->uid); - p9_put_str(bufp, wstat->gid, &stat->gid); - p9_put_str(bufp, wstat->muid, &stat->muid); - - if (dotu) { - p9_put_str(bufp, wstat->extension, &stat->extension); - p9_put_int32(bufp, wstat->n_uid, &stat->n_uid); - p9_put_int32(bufp, wstat->n_gid, &stat->n_gid); - p9_put_int32(bufp, wstat->n_muid, &stat->n_muid); - } -} - -static struct p9_fcall * -p9_create_common(struct cbuf *bufp, u32 size, u8 id) -{ - struct p9_fcall *fc; - - size += 4 + 1 + 2; /* size[4] id[1] tag[2] */ - fc = kmalloc(sizeof(struct p9_fcall) + size, GFP_KERNEL); - if (!fc) - return ERR_PTR(-ENOMEM); - - fc->sdata = (char *)fc + sizeof(*fc); - - buf_init(bufp, (char *)fc->sdata, size); - p9_put_int32(bufp, size, &fc->size); - p9_put_int8(bufp, id, &fc->id); - p9_put_int16(bufp, P9_NOTAG, &fc->tag); - - return fc; -} - -/** - * p9_set_tag - set the tag field of an &p9_fcall structure - * @fc: fcall structure to set tag within - * @tag: tag id to set - */ - -void p9_set_tag(struct p9_fcall *fc, u16 tag) -{ - fc->tag = tag; - *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag); -} -EXPORT_SYMBOL(p9_set_tag); - -/** - * p9_create_tversion - allocates and creates a T_VERSION request - * @msize: requested maximum data size - * @version: version string to negotiate - * - */ -struct p9_fcall *p9_create_tversion(u32 msize, char *version) -{ - int size; - struct p9_fcall *fc; - struct cbuf buffer; - struct cbuf *bufp = &buffer; - - size = 4 + 2 + strlen(version); /* msize[4] version[s] */ - fc = p9_create_common(bufp, size, P9_TVERSION); - if (IS_ERR(fc)) - goto error; - - p9_put_int32(bufp, msize, &fc->params.tversion.msize); - p9_put_str(bufp, version, &fc->params.tversion.version); - - if (buf_check_overflow(bufp)) { - kfree(fc); - fc = ERR_PTR(-ENOMEM); - } -error: - return fc; -} -EXPORT_SYMBOL(p9_create_tversion); - -/** - * p9_create_tauth - allocates and creates a T_AUTH request - * @afid: handle to use for authentication protocol - * @uname: user name attempting to authenticate - * @aname: mount specifier for remote server - * @n_uname: numeric id for user attempting to authneticate - * @dotu: 9P2000.u extension flag - * - */ - -struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname, - u32 n_uname, int dotu) -{ - int size; - struct p9_fcall *fc; - struct cbuf buffer; - struct cbuf *bufp = &buffer; - - /* afid[4] uname[s] aname[s] */ - size = 4 + 2 + 2; - if (uname) - size += strlen(uname); - - if (aname) - size += strlen(aname); - - if (dotu) - size += 4; /* n_uname */ - - fc = p9_create_common(bufp, size, P9_TAUTH); - if (IS_ERR(fc)) - goto error; - - p9_put_int32(bufp, afid, &fc->params.tauth.afid); - p9_put_str(bufp, uname, &fc->params.tauth.uname); - p9_put_str(bufp, aname, &fc->params.tauth.aname); - if (dotu) - p9_put_int32(bufp, n_uname, &fc->params.tauth.n_uname); - - if (buf_check_overflow(bufp)) { - kfree(fc); - fc = ERR_PTR(-ENOMEM); - } -error: - return fc; -} -EXPORT_SYMBOL(p9_create_tauth); - -/** - * p9_create_tattach - allocates and creates a T_ATTACH request - * @fid: handle to use for the new mount point - * @afid: handle to use for authentication protocol - * @uname: user name attempting to attach - * @aname: mount specifier for remote server - * @n_uname: numeric id for user attempting to attach - * @n_uname: numeric id for user attempting to attach - * @dotu: 9P2000.u extension flag - * - */ - -struct p9_fcall * -p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname, - u32 n_uname, int dotu) -{ - int size; - struct p9_fcall *fc; - struct cbuf buffer; - struct cbuf *bufp = &buffer; - - /* fid[4] afid[4] uname[s] aname[s] */ - size = 4 + 4 + 2 + 2; - if (uname) - size += strlen(uname); - - if (aname) - size += strlen(aname); - - if (dotu) - size += 4; /* n_uname */ - - fc = p9_create_common(bufp, size, P9_TATTACH); - if (IS_ERR(fc)) - goto error; - - p9_put_int32(bufp, fid, &fc->params.tattach.fid); - p9_put_int32(bufp, afid, &fc->params.tattach.afid); - p9_put_str(bufp, uname, &fc->params.tattach.uname); - p9_put_str(bufp, aname, &fc->params.tattach.aname); - if (dotu) - p9_put_int32(bufp, n_uname, &fc->params.tattach.n_uname); - -error: - return fc; -} -EXPORT_SYMBOL(p9_create_tattach); - -/** - * p9_create_tflush - allocates and creates a T_FLUSH request - * @oldtag: tag id for the transaction we are attempting to cancel - * - */ - -struct p9_fcall *p9_create_tflush(u16 oldtag) -{ - int size; - struct p9_fcall *fc; - struct cbuf buffer; - struct cbuf *bufp = &buffer; - - size = 2; /* oldtag[2] */ - fc = p9_create_common(bufp, size, P9_TFLUSH); - if (IS_ERR(fc)) - goto error; - - p9_put_int16(bufp, oldtag, &fc->params.tflush.oldtag); - - if (buf_check_overflow(bufp)) { - kfree(fc); - fc = ERR_PTR(-ENOMEM); - } -error: - return fc; -} -EXPORT_SYMBOL(p9_create_tflush); - -/** - * p9_create_twalk - allocates and creates a T_FLUSH request - * @fid: handle we are traversing from - * @newfid: a new handle for this transaction - * @nwname: number of path elements to traverse - * @wnames: array of path elements - * - */ - -struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname, - char **wnames) -{ - int i, size; - struct p9_fcall *fc; - struct cbuf buffer; - struct cbuf *bufp = &buffer; - - if (nwname > P9_MAXWELEM) { - P9_DPRINTK(P9_DEBUG_ERROR, "nwname > %d\n", P9_MAXWELEM); - return NULL; - } - - size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */ - for (i = 0; i < nwname; i++) { - size += 2 + strlen(wnames[i]); /* wname[s] */ - } - - fc = p9_create_common(bufp, size, P9_TWALK); - if (IS_ERR(fc)) - goto error; - - p9_put_int32(bufp, fid, &fc->params.twalk.fid); - p9_put_int32(bufp, newfid, &fc->params.twalk.newfid); - p9_put_int16(bufp, nwname, &fc->params.twalk.nwname); - for (i = 0; i < nwname; i++) { - p9_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]); - } - - if (buf_check_overflow(bufp)) { - kfree(fc); - fc = ERR_PTR(-ENOMEM); - } -error: - return fc; -} -EXPORT_SYMBOL(p9_create_twalk); - -/** - * p9_create_topen - allocates and creates a T_OPEN request - * @fid: handle we are trying to open - * @mode: what mode we are trying to open the file in - * - */ - -struct p9_fcall *p9_create_topen(u32 fid, u8 mode) -{ - int size; - struct p9_fcall *fc; - struct cbuf buffer; - struct cbuf *bufp = &buffer; - - size = 4 + 1; /* fid[4] mode[1] */ - fc = p9_create_common(bufp, size, P9_TOPEN); - if (IS_ERR(fc)) - goto error; - - p9_put_int32(bufp, fid, &fc->params.topen.fid); - p9_put_int8(bufp, mode, &fc->params.topen.mode); - - if (buf_check_overflow(bufp)) { - kfree(fc); - fc = ERR_PTR(-ENOMEM); - } -error: - return fc; -} -EXPORT_SYMBOL(p9_create_topen); - -/** - * p9_create_tcreate - allocates and creates a T_CREATE request - * @fid: handle of directory we are trying to create in - * @name: name of the file we are trying to create - * @perm: permissions for the file we are trying to create - * @mode: what mode we are trying to open the file in - * @extension: 9p2000.u extension string (for special files) - * @dotu: 9p2000.u enabled flag - * - * Note: Plan 9 create semantics include opening the resulting file - * which is why mode is included. - */ - -struct p9_fcall *p9_create_tcreate(u32 fid, char *name, u32 perm, u8 mode, - char *extension, int dotu) -{ - int size; - struct p9_fcall *fc; - struct cbuf buffer; - struct cbuf *bufp = &buffer; - - /* fid[4] name[s] perm[4] mode[1] */ - size = 4 + 2 + strlen(name) + 4 + 1; - if (dotu) { - size += 2 + /* extension[s] */ - (extension == NULL ? 0 : strlen(extension)); - } - - fc = p9_create_common(bufp, size, P9_TCREATE); - if (IS_ERR(fc)) - goto error; - - p9_put_int32(bufp, fid, &fc->params.tcreate.fid); - p9_put_str(bufp, name, &fc->params.tcreate.name); - p9_put_int32(bufp, perm, &fc->params.tcreate.perm); - p9_put_int8(bufp, mode, &fc->params.tcreate.mode); - if (dotu) - p9_put_str(bufp, extension, &fc->params.tcreate.extension); - - if (buf_check_overflow(bufp)) { - kfree(fc); - fc = ERR_PTR(-ENOMEM); - } -error: - return fc; -} -EXPORT_SYMBOL(p9_create_tcreate); - -/** - * p9_create_tread - allocates and creates a T_READ request - * @fid: handle of the file we are trying to read - * @offset: offset to start reading from - * @count: how many bytes to read - */ - -struct p9_fcall *p9_create_tread(u32 fid, u64 offset, u32 count) -{ - int size; - struct p9_fcall *fc; - struct cbuf buffer; - struct cbuf *bufp = &buffer; - - size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */ - fc = p9_create_common(bufp, size, P9_TREAD); - if (IS_ERR(fc)) - goto error; - - p9_put_int32(bufp, fid, &fc->params.tread.fid); - p9_put_int64(bufp, offset, &fc->params.tread.offset); - p9_put_int32(bufp, count, &fc->params.tread.count); - - if (buf_check_overflow(bufp)) { - kfree(fc); - fc = ERR_PTR(-ENOMEM); - } -error: - return fc; -} -EXPORT_SYMBOL(p9_create_tread); - -/** - * p9_create_twrite - allocates and creates a T_WRITE request from the kernel - * @fid: handle of the file we are trying to write - * @offset: offset to start writing at - * @count: how many bytes to write - * @data: data to write - * - * This function will create a requst with data buffers from the kernel - * such as the page cache. - */ - -struct p9_fcall *p9_create_twrite(u32 fid, u64 offset, u32 count, - const char *data) -{ - int size, err; - struct p9_fcall *fc; - struct cbuf buffer; - struct cbuf *bufp = &buffer; - - /* fid[4] offset[8] count[4] data[count] */ - size = 4 + 8 + 4 + count; - fc = p9_create_common(bufp, size, P9_TWRITE); - if (IS_ERR(fc)) - goto error; - - p9_put_int32(bufp, fid, &fc->params.twrite.fid); - p9_put_int64(bufp, offset, &fc->params.twrite.offset); - p9_put_int32(bufp, count, &fc->params.twrite.count); - err = p9_put_data(bufp, data, count, &fc->params.twrite.data); - if (err) { - kfree(fc); - fc = ERR_PTR(err); - goto error; - } - - if (buf_check_overflow(bufp)) { - kfree(fc); - fc = ERR_PTR(-ENOMEM); - } -error: - return fc; -} -EXPORT_SYMBOL(p9_create_twrite); - -/** - * p9_create_twrite_u - allocates and creates a T_WRITE request from userspace - * @fid: handle of the file we are trying to write - * @offset: offset to start writing at - * @count: how many bytes to write - * @data: data to write - * - * This function will create a request with data buffers from userspace - */ - -struct p9_fcall *p9_create_twrite_u(u32 fid, u64 offset, u32 count, - const char __user *data) -{ - int size, err; - struct p9_fcall *fc; - struct cbuf buffer; - struct cbuf *bufp = &buffer; - - /* fid[4] offset[8] count[4] data[count] */ - size = 4 + 8 + 4 + count; - fc = p9_create_common(bufp, size, P9_TWRITE); - if (IS_ERR(fc)) - goto error; - - p9_put_int32(bufp, fid, &fc->params.twrite.fid); - p9_put_int64(bufp, offset, &fc->params.twrite.offset); - p9_put_int32(bufp, count, &fc->params.twrite.count); - err = p9_put_user_data(bufp, data, count, &fc->params.twrite.data); - if (err) { - kfree(fc); - fc = ERR_PTR(err); - goto error; - } - - if (buf_check_overflow(bufp)) { - kfree(fc); - fc = ERR_PTR(-ENOMEM); - } -error: - return fc; -} -EXPORT_SYMBOL(p9_create_twrite_u); - -/** - * p9_create_tclunk - allocate a request to forget about a file handle - * @fid: handle of the file we closing or forgetting about - * - * clunk is used both to close open files and to discard transient handles - * which may be created during meta-data operations and hierarchy traversal. - */ - -struct p9_fcall *p9_create_tclunk(u32 fid) -{ - int size; - struct p9_fcall *fc; - struct cbuf buffer; - struct cbuf *bufp = &buffer; - - size = 4; /* fid[4] */ - fc = p9_create_common(bufp, size, P9_TCLUNK); - if (IS_ERR(fc)) - goto error; - - p9_put_int32(bufp, fid, &fc->params.tclunk.fid); - - if (buf_check_overflow(bufp)) { - kfree(fc); - fc = ERR_PTR(-ENOMEM); - } -error: - return fc; -} -EXPORT_SYMBOL(p9_create_tclunk); - -/** - * p9_create_tremove - allocate and create a request to remove a file - * @fid: handle of the file or directory we are removing - * - */ - -struct p9_fcall *p9_create_tremove(u32 fid) -{ - int size; - struct p9_fcall *fc; - struct cbuf buffer; - struct cbuf *bufp = &buffer; - - size = 4; /* fid[4] */ - fc = p9_create_common(bufp, size, P9_TREMOVE); - if (IS_ERR(fc)) - goto error; - - p9_put_int32(bufp, fid, &fc->params.tremove.fid); - - if (buf_check_overflow(bufp)) { - kfree(fc); - fc = ERR_PTR(-ENOMEM); - } -error: - return fc; -} -EXPORT_SYMBOL(p9_create_tremove); - -/** - * p9_create_tstat - allocate and populate a request for attributes - * @fid: handle of the file or directory we are trying to get the attributes of - * - */ - -struct p9_fcall *p9_create_tstat(u32 fid) -{ - int size; - struct p9_fcall *fc; - struct cbuf buffer; - struct cbuf *bufp = &buffer; - - size = 4; /* fid[4] */ - fc = p9_create_common(bufp, size, P9_TSTAT); - if (IS_ERR(fc)) - goto error; - - p9_put_int32(bufp, fid, &fc->params.tstat.fid); - - if (buf_check_overflow(bufp)) { - kfree(fc); - fc = ERR_PTR(-ENOMEM); - } -error: - return fc; -} -EXPORT_SYMBOL(p9_create_tstat); - -/** - * p9_create_tstat - allocate and populate a request to change attributes - * @fid: handle of the file or directory we are trying to change - * @wstat: &p9_stat structure with attributes we wish to set - * @dotu: 9p2000.u enabled flag - * - */ - -struct p9_fcall *p9_create_twstat(u32 fid, struct p9_wstat *wstat, - int dotu) -{ - int size, statsz; - struct p9_fcall *fc; - struct cbuf buffer; - struct cbuf *bufp = &buffer; - - statsz = p9_size_wstat(wstat, dotu); - size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */ - fc = p9_create_common(bufp, size, P9_TWSTAT); - if (IS_ERR(fc)) - goto error; - - p9_put_int32(bufp, fid, &fc->params.twstat.fid); - buf_put_int16(bufp, statsz + 2); - p9_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, dotu); - - if (buf_check_overflow(bufp)) { - kfree(fc); - fc = ERR_PTR(-ENOMEM); - } -error: - return fc; -} -EXPORT_SYMBOL(p9_create_twstat); - diff --git a/net/9p/protocol.c b/net/9p/protocol.c index 4ebeffd21d3d..92cb60bb191b 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c @@ -509,6 +509,19 @@ p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...) return ret; } +int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu) +{ + struct p9_fcall fake_pdu; + + fake_pdu.size = len; + fake_pdu.capacity = len; + fake_pdu.sdata = buf; + fake_pdu.offset = 0; + + return p9pdu_readf(&fake_pdu, dotu, "S", st); +} +EXPORT_SYMBOL(p9stat_read); + int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type) { return p9pdu_writef(pdu, 0, "dbw", 0, type, tag); From e7f4b8f1a5893ff8296b5b581e16a0b96f60a3b5 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Fri, 17 Oct 2008 16:20:07 -0500 Subject: [PATCH 23/26] 9p: Improve debug support The new debug support lacks some of the information that the previous fcprint code provided -- this patch focuses on better presentation of debug data along with more helpful debug along error paths. Signed-off-by: Eric Van Hensbergen --- include/net/9p/9p.h | 4 +-- net/9p/client.c | 76 ++++++++++++++++++++++++++++++++------------- net/9p/protocol.c | 21 +++++++++---- 3 files changed, 72 insertions(+), 29 deletions(-) diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index cb5bc731e885..d2c60c73619d 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h @@ -27,8 +27,6 @@ #ifndef NET_9P_H #define NET_9P_H -#ifdef CONFIG_NET_9P_DEBUG - /** * enum p9_debug_flags - bits for mount time debug parameter * @P9_DEBUG_ERROR: more verbose error messages including original error string @@ -55,10 +53,12 @@ enum p9_debug_flags { P9_DEBUG_SLABS = (1<<7), P9_DEBUG_FCALL = (1<<8), P9_DEBUG_FID = (1<<9), + P9_DEBUG_PKT = (1<<10), }; extern unsigned int p9_debug_level; +#ifdef CONFIG_NET_9P_DEBUG #define P9_DPRINTK(level, format, arg...) \ do { \ if ((p9_debug_level & level) == level) {\ diff --git a/net/9p/client.c b/net/9p/client.c index 2a166bfb95a3..bbac2f72b4d2 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -389,8 +389,8 @@ p9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type, int16_t *tag, 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); + P9_DPRINTK(P9_DEBUG_9P, "<<< size=%d type: %d tag: %d\n", pdu->size, + pdu->id, pdu->tag); if (type) *type = r_type; @@ -672,6 +672,7 @@ int p9_client_version(struct p9_client *c) err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version); if (err) { P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); + p9pdu_dump(1, req->rc); goto error; } @@ -810,6 +811,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); if (err) { + p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto error; } @@ -856,6 +858,7 @@ p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname) err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); if (err) { + p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto error; } @@ -910,9 +913,12 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, } err = p9pdu_readf(req->rc, clnt->dotu, "R", &nwqids, &wqids); - p9_free_req(clnt, req); - if (err) + if (err) { + p9pdu_dump(1, req->rc); + p9_free_req(clnt, req); goto clunk_fid; + } + p9_free_req(clnt, req); P9_DPRINTK(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids); @@ -967,9 +973,10 @@ int p9_client_open(struct p9_fid *fid, int mode) } err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); - p9_free_req(clnt, req); - if (err) - goto error; + if (err) { + p9pdu_dump(1, req->rc); + goto free_and_error; + } P9_DPRINTK(P9_DEBUG_9P, "<<< ROPEN qid %x.%llx.%x iounit %x\n", qid.type, qid.path, qid.version, iounit); @@ -977,6 +984,8 @@ int p9_client_open(struct p9_fid *fid, int mode) fid->mode = mode; fid->iounit = iounit; +free_and_error: + p9_free_req(clnt, req); error: return err; } @@ -1007,9 +1016,10 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, } err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); - p9_free_req(clnt, req); - if (err) - goto error; + if (err) { + p9pdu_dump(1, req->rc); + goto free_and_error; + } P9_DPRINTK(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n", qid.type, qid.path, qid.version, iounit); @@ -1017,6 +1027,8 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, fid->mode = mode; fid->iounit = iounit; +free_and_error: + p9_free_req(clnt, req); error: return err; } @@ -1103,8 +1115,10 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, } err = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr); - if (err) + if (err) { + p9pdu_dump(1, req->rc); goto free_and_error; + } P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); @@ -1163,8 +1177,11 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, } err = p9pdu_readf(req->rc, clnt->dotu, "d", &count); - if (err) + if (err) { + p9pdu_dump(1, req->rc); goto free_and_error; + } + P9_DPRINTK(P9_DEBUG_9P, "<<< RWRITE count %d\n", count); p9_free_req(clnt, req); @@ -1200,20 +1217,27 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid) } err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret); - p9_free_req(clnt, req); - if (err) - goto error; + if (err) { + ret = ERR_PTR(err); + p9pdu_dump(1, req->rc); + goto free_and_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", + "<<< RSTAT sz=%x type=%x dev=%x qid=%x.%llx.%x\n" + "<<< mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n" + "<<< name=%s uid=%s gid=%s muid=%s extension=(%s)\n" + "<<< uid=%d gid=%d n_muid=%d\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); + ret->qid.path, ret->qid.version, ret->mode, + ret->atime, ret->mtime, ret->length, ret->name, + ret->uid, ret->gid, ret->muid, ret->extension, + ret->n_uid, ret->n_gid, ret->n_muid); - return ret; +free_and_error: + p9_free_req(clnt, req); error: - return ERR_PTR(err); + return ret; } EXPORT_SYMBOL(p9_client_stat); @@ -1224,6 +1248,16 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst) struct p9_client *clnt; P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid); + P9_DPRINTK(P9_DEBUG_9P, + " sz=%x type=%x dev=%x qid=%x.%llx.%x\n" + " mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n" + " name=%s uid=%s gid=%s muid=%s extension=(%s)\n" + " uid=%d gid=%d n_muid=%d\n", + wst->size, wst->type, wst->dev, wst->qid.type, + wst->qid.path, wst->qid.version, wst->mode, + wst->atime, wst->mtime, wst->length, wst->name, + wst->uid, wst->gid, wst->muid, wst->extension, + wst->n_uid, wst->n_gid, wst->n_muid); err = 0; clnt = fid->clnt; diff --git a/net/9p/protocol.c b/net/9p/protocol.c index 92cb60bb191b..84fa21271876 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include "protocol.h" @@ -52,8 +53,6 @@ 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) { @@ -78,9 +77,9 @@ p9pdu_dump(int way, struct p9_fcall *pdu) n += scnprintf(buf + n, buflen - n, "\n"); if (way) - printk(KERN_NOTICE "[[(%d)[ %s\n", datalen, buf); + P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf); else - printk(KERN_NOTICE "]](%d)] %s\n", datalen, buf); + P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf); } EXPORT_SYMBOL(p9pdu_dump); @@ -512,13 +511,20 @@ p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...) int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu) { struct p9_fcall fake_pdu; + int ret; fake_pdu.size = len; fake_pdu.capacity = len; fake_pdu.sdata = buf; fake_pdu.offset = 0; - return p9pdu_readf(&fake_pdu, dotu, "S", st); + ret = p9pdu_readf(&fake_pdu, dotu, "S", st); + if (ret) { + P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); + p9pdu_dump(1, &fake_pdu); + } + + return ret; } EXPORT_SYMBOL(p9stat_read); @@ -536,9 +542,12 @@ int p9pdu_finalize(struct p9_fcall *pdu) err = p9pdu_writef(pdu, 0, "d", size); pdu->size = size; - if (PACKET_DEBUG) + if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT) p9pdu_dump(0, pdu); + P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size, + pdu->id, pdu->tag); + return err; } From 57c7b4e68edf3b4fe7f977db9ad437e0f7f7c382 Mon Sep 17 00:00:00 2001 From: Magnus Deininger Date: Fri, 17 Oct 2008 12:44:46 -0500 Subject: [PATCH 24/26] 9p: fix device file handling In v9fs_get_inode(), for block, as well as char devices (in theory), the function init_special_inode() is called to set up callback functions for file ops. this function uses the file mode's value to determine whether to use block or char dev functions. In v9fs_inode_from_fid(), the function p9mode2unixmode() is used, but for all devices it initially returns S_IFBLK, then uses v9fs_get_inode() to initialise a new inode, then finally uses v9fs_stat2inode(), which would determine whether the inode is a block or character device. However, at that point init_special_inode() had already decided to use the block device functions, so even if the inode's mode is turned to a character device, the block functions are still used to operate on them. The attached patch simply calls init_special_inode() again for devices after parsing device node data in v9fs_stat2inode() so that the proper functions are used. Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index e96d84aafbe2..8314d3f43b71 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -864,6 +864,7 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, stat->extension); }; inode->i_rdev = MKDEV(major, minor); + init_special_inode(inode, inode->i_mode, inode->i_rdev); } else inode->i_rdev = 0; From f0a0ac2ee50c62cf4ad9b06cf8a12435cc5ac44d Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Fri, 17 Oct 2008 12:45:23 -0500 Subject: [PATCH 25/26] 9p: fix oops in protocol stat parsing error path. When we get an error on parsing a stat due to a protocol bug, we can generate an oops during cleanup because we didn't initialize the string pointers in the stat structure. Signed-off-by: Eric Van Hensbergen --- net/9p/protocol.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/9p/protocol.c b/net/9p/protocol.c index 84fa21271876..29be52439086 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c @@ -215,9 +215,9 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) struct p9_wstat *stbuf = va_arg(ap, struct p9_wstat *); - stbuf->extension = NULL; + memset(stbuf, 0, sizeof(struct p9_wstat)); stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = - -1; + -1; errcode = p9pdu_readf(pdu, optional, "wwdQdddqssss?sddd", From 7eb923b80c8ce16697129fb2dcdfaeabf83f0dbc Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Fri, 17 Oct 2008 12:45:40 -0500 Subject: [PATCH 26/26] 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(-) 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; } /**