diff options
Diffstat (limited to 'net')
98 files changed, 2118 insertions, 1822 deletions
diff --git a/net/9p/Makefile b/net/9p/Makefile index d3abb246ccab..8a1051101898 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 \ - mux.o \ client.o \ conv.o \ error.o \ diff --git a/net/9p/client.c b/net/9p/client.c index af9199364049..84e087e24146 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -3,6 +3,7 @@ * * 9P Client * + * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com> * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net> * * This program is free software; you can redistribute it and/or modify @@ -25,6 +26,7 @@ #include <linux/module.h> #include <linux/errno.h> #include <linux/fs.h> +#include <linux/poll.h> #include <linux/idr.h> #include <linux/mutex.h> #include <linux/sched.h> @@ -32,15 +34,97 @@ #include <net/9p/9p.h> #include <linux/parser.h> #include <net/9p/transport.h> -#include <net/9p/conn.h> #include <net/9p/client.h> 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); -struct p9_client *p9_client_create(struct p9_trans *trans, int msize, - int dotu) +/* + * Client Option Parsing (code inspired by NFS code) + * - a little lazy - parse all client options + */ + +enum { + Opt_msize, + Opt_trans, + Opt_legacy, + Opt_err, +}; + +static match_table_t tokens = { + {Opt_msize, "msize=%u"}, + {Opt_legacy, "noextend"}, + {Opt_trans, "trans=%s"}, + {Opt_err, NULL}, +}; + +/** + * v9fs_parse_options - parse mount options into session structure + * @options: options string passed from mount + * @v9ses: existing v9fs session information + * + */ + +static void parse_opts(char *options, struct p9_client *clnt) +{ + char *p; + substring_t args[MAX_OPT_ARGS]; + int option; + int ret; + + clnt->trans_mod = v9fs_default_trans(); + clnt->dotu = 1; + clnt->msize = 8192; + + if (!options) + return; + + while ((p = strsep(&options, ",")) != NULL) { + int token; + if (!*p) + continue; + token = match_token(p, tokens, args); + if (token < Opt_trans) { + ret = match_int(&args[0], &option); + if (ret < 0) { + P9_DPRINTK(P9_DEBUG_ERROR, + "integer field, but no integer?\n"); + continue; + } + } + switch (token) { + case Opt_msize: + clnt->msize = option; + break; + case Opt_trans: + clnt->trans_mod = v9fs_match_trans(&args[0]); + break; + case Opt_legacy: + clnt->dotu = 0; + break; + default: + continue; + } + } +} + + +/** + * 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->rpc(c->trans, tc, rc); +} + +struct p9_client *p9_client_create(const char *dev_name, char *options) { int err, n; struct p9_client *clnt; @@ -54,12 +138,7 @@ struct p9_client *p9_client_create(struct p9_trans *trans, int msize, if (!clnt) return ERR_PTR(-ENOMEM); - P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n", - clnt, trans, msize, dotu); spin_lock_init(&clnt->lock); - clnt->trans = trans; - clnt->msize = msize; - clnt->dotu = dotu; INIT_LIST_HEAD(&clnt->fidlist); clnt->fidpool = p9_idpool_create(); if (!clnt->fidpool) { @@ -68,13 +147,29 @@ struct p9_client *p9_client_create(struct p9_trans *trans, int msize, goto error; } - clnt->conn = p9_conn_create(clnt->trans, clnt->msize, &clnt->dotu); - if (IS_ERR(clnt->conn)) { - err = PTR_ERR(clnt->conn); - clnt->conn = NULL; + parse_opts(options, clnt); + if (clnt->trans_mod == NULL) { + err = -EPROTONOSUPPORT; + P9_DPRINTK(P9_DEBUG_ERROR, + "No transport defined or default transport\n"); goto error; } + P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n", + 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; + goto error; + } + + 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); @@ -82,7 +177,7 @@ struct p9_client *p9_client_create(struct p9_trans *trans, int msize, goto error; } - err = p9_conn_rpc(clnt->conn, tc, &rc); + err = p9_client_rpc(clnt, tc, &rc); if (err) goto error; @@ -117,10 +212,6 @@ void p9_client_destroy(struct p9_client *clnt) struct p9_fid *fid, *fidptr; P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); - if (clnt->conn) { - p9_conn_destroy(clnt->conn); - clnt->conn = NULL; - } if (clnt->trans) { clnt->trans->close(clnt->trans); @@ -142,7 +233,6 @@ void p9_client_disconnect(struct p9_client *clnt) { P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); clnt->trans->status = Disconnected; - p9_conn_cancel(clnt->conn, -EIO); } EXPORT_SYMBOL(p9_client_disconnect); @@ -174,7 +264,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, goto error; } - err = p9_conn_rpc(clnt->conn, tc, &rc); + err = p9_client_rpc(clnt, tc, &rc); if (err) goto error; @@ -219,7 +309,7 @@ struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, goto error; } - err = p9_conn_rpc(clnt->conn, tc, &rc); + err = p9_client_rpc(clnt, tc, &rc); if (err) goto error; @@ -270,7 +360,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, goto error; } - err = p9_conn_rpc(clnt->conn, tc, &rc); + err = p9_client_rpc(clnt, tc, &rc); if (err) { if (rc && rc->id == P9_RWALK) goto clunk_fid; @@ -305,7 +395,7 @@ clunk_fid: goto error; } - p9_conn_rpc(clnt->conn, tc, &rc); + p9_client_rpc(clnt, tc, &rc); error: kfree(tc); @@ -339,7 +429,7 @@ int p9_client_open(struct p9_fid *fid, int mode) goto done; } - err = p9_conn_rpc(clnt->conn, tc, &rc); + err = p9_client_rpc(clnt, tc, &rc); if (err) goto done; @@ -378,7 +468,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, goto done; } - err = p9_conn_rpc(clnt->conn, tc, &rc); + err = p9_client_rpc(clnt, tc, &rc); if (err) goto done; @@ -411,7 +501,7 @@ int p9_client_clunk(struct p9_fid *fid) goto done; } - err = p9_conn_rpc(clnt->conn, tc, &rc); + err = p9_client_rpc(clnt, tc, &rc); if (err) goto done; @@ -443,7 +533,7 @@ int p9_client_remove(struct p9_fid *fid) goto done; } - err = p9_conn_rpc(clnt->conn, tc, &rc); + err = p9_client_rpc(clnt, tc, &rc); if (err) goto done; @@ -485,7 +575,7 @@ int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count) goto error; } - err = p9_conn_rpc(clnt->conn, tc, &rc); + err = p9_client_rpc(clnt, tc, &rc); if (err) goto error; @@ -542,7 +632,7 @@ int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count) goto error; } - err = p9_conn_rpc(clnt->conn, tc, &rc); + err = p9_client_rpc(clnt, tc, &rc); if (err) goto error; @@ -596,7 +686,7 @@ p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count) goto error; } - err = p9_conn_rpc(clnt->conn, tc, &rc); + err = p9_client_rpc(clnt, tc, &rc); if (err) goto error; @@ -660,7 +750,7 @@ p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset, goto error; } - err = p9_conn_rpc(clnt->conn, tc, &rc); + err = p9_client_rpc(clnt, tc, &rc); if (err) goto error; @@ -731,7 +821,7 @@ struct p9_stat *p9_client_stat(struct p9_fid *fid) goto error; } - err = p9_conn_rpc(clnt->conn, tc, &rc); + err = p9_client_rpc(clnt, tc, &rc); if (err) goto error; @@ -773,7 +863,7 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst) goto done; } - err = p9_conn_rpc(clnt->conn, tc, &rc); + err = p9_client_rpc(clnt, tc, &rc); done: kfree(tc); @@ -830,7 +920,7 @@ struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset) goto error; } - err = p9_conn_rpc(clnt->conn, tc, &rc); + err = p9_client_rpc(clnt, tc, &rc); if (err) goto error; @@ -901,16 +991,21 @@ static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu) 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; } diff --git a/net/9p/fcprint.c b/net/9p/fcprint.c index b1ae8ec57d54..40244fbd9b0d 100644 --- a/net/9p/fcprint.c +++ b/net/9p/fcprint.c @@ -347,12 +347,12 @@ p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended) return ret; } - #else int p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended) { return 0; } -EXPORT_SYMBOL(p9_printfcall); #endif /* CONFIG_NET_9P_DEBUG */ +EXPORT_SYMBOL(p9_printfcall); + diff --git a/net/9p/mod.c b/net/9p/mod.c index 8f9763a9dc12..c285aab2af04 100644 --- a/net/9p/mod.c +++ b/net/9p/mod.c @@ -106,15 +106,10 @@ EXPORT_SYMBOL(v9fs_default_trans); */ static int __init init_p9(void) { - int ret; + int ret = 0; p9_error_init(); printk(KERN_INFO "Installing 9P2000 support\n"); - ret = p9_mux_global_init(); - if (ret) { - printk(KERN_WARNING "9p: starting mux failed\n"); - return ret; - } return ret; } @@ -126,7 +121,7 @@ static int __init init_p9(void) static void __exit exit_p9(void) { - p9_mux_global_exit(); + printk(KERN_INFO "Unloading 9P2000 support\n"); } module_init(init_p9) diff --git a/net/9p/mux.c b/net/9p/mux.c deleted file mode 100644 index c9f0805048e4..000000000000 --- a/net/9p/mux.c +++ /dev/null @@ -1,1060 +0,0 @@ -/* - * net/9p/mux.c - * - * Protocol Multiplexer - * - * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> - * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> - * - * 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 <linux/module.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/poll.h> -#include <linux/kthread.h> -#include <linux/idr.h> -#include <linux/mutex.h> -#include <net/9p/9p.h> -#include <linux/parser.h> -#include <net/9p/transport.h> -#include <net/9p/conn.h> - -#define ERREQFLUSH 1 -#define SCHED_TIMEOUT 10 -#define MAXPOLLWADDR 2 - -enum { - Rworksched = 1, /* read work scheduled or running */ - Rpending = 2, /* can read */ - Wworksched = 4, /* write work scheduled or running */ - Wpending = 8, /* can write */ -}; - -enum { - None, - Flushing, - Flushed, -}; - -struct p9_mux_poll_task; - -struct p9_req { - spinlock_t lock; /* protect request structure */ - int tag; - 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 { - 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; - struct p9_idpool *tagpool; - int err; - wait_queue_head_t equeue; - struct list_head req_list; - struct list_head unsent_req_list; - struct p9_fcall *rcall; - int rpos; - char *rbuf; - int wpos; - int wsize; - char *wbuf; - wait_queue_t poll_wait[MAXPOLLWADDR]; - wait_queue_head_t *poll_waddr[MAXPOLLWADDR]; - poll_table pt; - struct work_struct rq; - struct work_struct wq; - unsigned long wsched; -}; - -struct p9_mux_poll_task { - struct task_struct *task; - struct list_head mux_list; - int muxnum; -}; - -struct p9_mux_rpc { - struct p9_conn *m; - int err; - struct p9_fcall *tcall; - struct p9_fcall *rcall; - 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 u16 p9_mux_get_tag(struct p9_conn *); -static void p9_mux_put_tag(struct p9_conn *, u16); - -static DEFINE_MUTEX(p9_mux_task_lock); -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]; - -int p9_mux_global_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; - } - - return 0; -} - -void p9_mux_global_exit(void) -{ - destroy_workqueue(p9_mux_wq); -} - -/** - * p9_mux_calc_poll_procs - calculates the number of polling procs - * 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) -{ - int i; - struct p9_mux_poll_task *vpt; - - mutex_lock(&p9_mux_task_lock); - vpt = m->poll_task; - list_del(&m->mux_list); - for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { - if (m->poll_waddr[i] != NULL) { - remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]); - m->poll_waddr[i] = NULL; - } - } - vpt->muxnum--; - if (!vpt->muxnum) { - P9_DPRINTK(P9_DEBUG_MUX, "destroy proc %p\n", vpt); - kthread_stop(vpt->task); - vpt->task = NULL; - p9_mux_poll_task_num--; - } - p9_mux_num--; - mutex_unlock(&p9_mux_task_lock); -} - -/** - * p9_conn_create - allocate and initialize the per-session mux data - * Creates the polling task if this is the first session. - * - * @trans - transport structure - * @msize - maximum message size - * @extended - pointer to the extended flag - */ -struct p9_conn *p9_conn_create(struct p9_trans *trans, int msize, - unsigned char *extended) -{ - int i, n; - struct p9_conn *m, *mtmp; - - P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans, msize); - m = kmalloc(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 = msize; - m->extended = extended; - m->trans = trans; - m->tagpool = p9_idpool_create(); - if (IS_ERR(m->tagpool)) { - mtmp = ERR_PTR(-ENOMEM); - kfree(m); - return mtmp; - } - - m->err = 0; - init_waitqueue_head(&m->equeue); - INIT_LIST_HEAD(&m->req_list); - INIT_LIST_HEAD(&m->unsent_req_list); - m->rcall = NULL; - m->rpos = 0; - m->rbuf = NULL; - m->wpos = m->wsize = 0; - m->wbuf = NULL; - INIT_WORK(&m->rq, p9_read_work); - INIT_WORK(&m->wq, p9_write_work); - m->wsched = 0; - memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); - m->poll_task = NULL; - n = p9_mux_poll_start(m); - if (n) { - kfree(m); - return ERR_PTR(n); - } - - n = trans->poll(trans, &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_waddr); i++) { - if (IS_ERR(m->poll_waddr[i])) { - p9_mux_poll_stop(m); - mtmp = (void *)m->poll_waddr; /* the error code */ - kfree(m); - m = mtmp; - break; - } - } - - return m; -} -EXPORT_SYMBOL(p9_conn_create); - -/** - * p9_mux_destroy - cancels all pending requests and frees mux resources - */ -void p9_conn_destroy(struct p9_conn *m) -{ - P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m, - m->mux_list.prev, m->mux_list.next); - p9_conn_cancel(m, -ECONNRESET); - - if (!list_empty(&m->req_list)) { - /* wait until all processes waiting on this session exit */ - P9_DPRINTK(P9_DEBUG_MUX, - "mux %p waiting for empty request queue\n", m); - wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000); - P9_DPRINTK(P9_DEBUG_MUX, "mux %p request queue empty: %d\n", m, - list_empty(&m->req_list)); - } - - p9_mux_poll_stop(m); - m->trans = NULL; - p9_idpool_destroy(m->tagpool); - kfree(m); -} -EXPORT_SYMBOL(p9_conn_destroy); - -/** - * p9_pollwait - 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) -{ - 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) - break; - - if (i >= ARRAY_SIZE(m->poll_waddr)) { - 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); - return; - } - - init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task); - add_wait_queue(wait_address, &m->poll_wait[i]); -} - -/** - * p9_poll_mux - polls a mux and schedules read or write works if necessary - */ -static void p9_poll_mux(struct p9_conn *m) -{ - int n; - - if (m->err < 0) - return; - - n = m->trans->poll(m->trans, 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 - polls all v9fs transports for new events and queues - * the appropriate work to the work queue - */ -static int p9_poll_proc(void *a) -{ - struct p9_conn *m, *mtmp; - struct p9_mux_poll_task *vpt; - - vpt = a; - P9_DPRINTK(P9_DEBUG_MUX, "start %p %p\n", current, vpt); - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - - list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) { - p9_poll_mux(m); - } - - P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n"); - schedule_timeout(SCHED_TIMEOUT * HZ); - } - - __set_current_state(TASK_RUNNING); - P9_DPRINTK(P9_DEBUG_MUX, "finish\n"); - return 0; -} - -/** - * p9_write_work - called when a transport can send some data - */ -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 = m->trans->write(m->trans, 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 = m->trans->poll(m->trans, 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 void process_request(struct p9_conn *m, struct p9_req *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; - - P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len, - ename->str); - - if (*m->extended) - req->err = -ecode; - - if (!req->err) { - req->err = p9_errstr2errno(ename->str, ename->len); - - if (!req->err) { /* string match failed */ - PRINT_FCALL_ERROR("unknown error", req->rcall); - } - - if (!req->err) - req->err = -ESERVERFAULT; - } - } else if (req->tcall && req->rcall->id != req->tcall->id + 1) { - P9_DPRINTK(P9_DEBUG_ERROR, - "fcall mismatch: expected %d, got %d\n", - req->tcall->id + 1, req->rcall->id); - if (!req->err) - req->err = -EIO; - } -} - -/** - * p9_read_work - called when there is some data to be read from a transport - */ -static void p9_read_work(struct work_struct *work) -{ - int n, err; - struct p9_conn *m; - struct p9_req *req, *rptr, *rreq; - struct p9_fcall *rcall; - char *rbuf; - - m = container_of(work, struct p9_conn, rq); - - if (m->err < 0) - return; - - rcall = NULL; - P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); - - if (!m->rcall) { - m->rcall = - kmalloc(sizeof(struct p9_fcall) + m->msize, GFP_KERNEL); - if (!m->rcall) { - err = -ENOMEM; - goto error; - } - - m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall); - m->rpos = 0; - } - - clear_bit(Rpending, &m->wsched); - err = m->trans->read(m->trans, 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); - return; - } - - if (err <= 0) - goto error; - - m->rpos += err; - while (m->rpos > 4) { - n = le32_to_cpu(*(__le32 *) m->rbuf); - if (n >= m->msize) { - P9_DPRINTK(P9_DEBUG_ERROR, - "requested packet size too big: %d\n", n); - err = -EIO; - goto error; - } - - if (m->rpos < n) - break; - - err = - p9_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended); - if (err < 0) { - goto error; - } - -#ifdef CONFIG_NET_9P_DEBUG - if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { - char buf[150]; - - p9_printfcall(buf, sizeof(buf), m->rcall, - *m->extended); - 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->msize, - GFP_KERNEL); - if (!m->rcall) { - err = -ENOMEM; - goto error; - } - - m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall); - memmove(m->rbuf, rbuf + n, m->rpos - n); - m->rpos -= n; - } else { - m->rcall = NULL; - m->rbuf = NULL; - m->rpos = 0; - } - - P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, - rcall->id, rcall->tag); - - req = NULL; - spin_lock(&m->lock); - list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { - if (rreq->tag == rcall->tag) { - req = rreq; - if (req->flush != Flushing) - list_del(&req->req_list); - break; - } - } - spin_unlock(&m->lock); - - if (req) { - req->rcall = rcall; - process_request(m, req); - - if (req->flush != Flushing) { - if (req->cb) - (*req->cb) (req, req->cba); - else - kfree(req->rcall); - - wake_up(&m->equeue); - } - } else { - if (err >= 0 && rcall->id != P9_RFLUSH) - P9_DPRINTK(P9_DEBUG_ERROR, - "unexpected response mux %p id %d tag %d\n", - m, rcall->id, rcall->tag); - kfree(rcall); - } - } - - if (!list_empty(&m->req_list)) { - if (test_and_clear_bit(Rpending, &m->wsched)) - n = POLLIN; - else - n = m->trans->poll(m->trans, NULL); - - if (n & POLLIN) { - P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m); - queue_work(p9_mux_wq, &m->rq); - } else - clear_bit(Rworksched, &m->wsched); - } else - clear_bit(Rworksched, &m->wsched); - - return; - -error: - p9_conn_cancel(m, err); - clear_bit(Rworksched, &m->wsched); -} - -/** - * p9_send_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. - * - * @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) -{ - int n; - struct p9_req *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); - - if (tc->id == P9_TVERSION) - n = P9_NOTAG; - else - n = p9_mux_get_tag(m); - - if (n < 0) - return ERR_PTR(-ENOMEM); - - p9_set_tag(tc, n); - -#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->extended); - printk(KERN_NOTICE "<<< %p %s\n", m, buf); - } -#endif - - spin_lock_init(&req->lock); - req->tag = n; - req->tcall = tc; - req->rcall = NULL; - req->err = 0; - req->cb = cb; - req->cba = cba; - req->flush = None; - - spin_lock(&m->lock); - list_add_tail(&req->req_list, &m->unsent_req_list); - spin_unlock(&m->lock); - - if (test_and_clear_bit(Wpending, &m->wsched)) - n = POLLOUT; - else - n = m->trans->poll(m->trans, NULL); - - if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched)) - queue_work(p9_mux_wq, &m->wq); - - 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) -{ - p9_conn_req_callback cb; - 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); - cb = NULL; - 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); - - wake_up(&m->equeue); - } - - 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) -{ - struct p9_fcall *fc; - struct p9_req *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); - P9_DPRINTK(P9_DEBUG_MUX, - "mux %p req %p response already received\n", m, req); - return 0; - } - - req->flush = Flushing; - spin_unlock(&req->lock); - - spin_lock(&m->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); - if (req->cb) - (*req->cb) (req, req->cba); - return 0; - } - } - spin_unlock(&m->lock); - - clear_thread_flag(TIF_SIGPENDING); - fc = p9_create_tflush(req->tag); - p9_send_request(m, fc, p9_mux_flush_cb, m); - return 1; -} - -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; - - if (req->flush != None && !req->err) - r->err = -ERESTARTSYS; - - wake_up(&r->wqueue); -} - -/** - * p9_mux_rpc - sends 9P request and waits until a response is available. - * The function can be interrupted. - * @m: mux data - * @tc: request to be sent - * @rc: pointer where a pointer to the response is stored - */ -int -p9_conn_rpc(struct p9_conn *m, 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; - - sigpending = 0; - if (signal_pending(current)) { - sigpending = 1; - clear_thread_flag(TIF_SIGPENDING); - } - - req = p9_send_request(m, tc, p9_conn_rpc_cb, &r); - 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; - - if (err == -ERESTARTSYS && m->trans->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(r.wqueue, - r.rcall || r.err); - } while (!r.rcall && !r.err && err == -ERESTARTSYS && - m->trans->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 = r.rcall; - else - kfree(r.rcall); - - p9_mux_free_request(m, req); - if (err > 0) - err = -EIO; - - return err; -} -EXPORT_SYMBOL(p9_conn_rpc); - -#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 - * @cba: 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; -} -EXPORT_SYMBOL(p9_conn_rpcnb); -#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); - } - - wake_up(&m->equeue); -} -EXPORT_SYMBOL(p9_conn_cancel); - -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); -} diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 62332ed9da4a..1aa9d5175398 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -5,7 +5,7 @@ * * Copyright (C) 2006 by Russ Cox <rsc@swtch.com> * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> - * Copyright (C) 2004-2007 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com> * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com> * * This program is free software; you can redistribute it and/or modify @@ -29,6 +29,7 @@ #include <linux/module.h> #include <linux/net.h> #include <linux/ipv6.h> +#include <linux/kthread.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/un.h> @@ -42,7 +43,9 @@ #define P9_PORT 564 #define MAX_SOCK_BUF (64*1024) - +#define ERREQFLUSH 1 +#define SCHED_TIMEOUT 10 +#define MAXPOLLWADDR 2 struct p9_fd_opts { int rfd; @@ -53,6 +56,7 @@ struct p9_fd_opts { struct p9_trans_fd { struct file *rd; struct file *wr; + struct p9_conn *conn; }; /* @@ -72,6 +76,1028 @@ static match_table_t tokens = { {Opt_err, NULL}, }; +enum { + Rworksched = 1, /* read work scheduled or running */ + Rpending = 2, /* can read */ + Wworksched = 4, /* write work scheduled or running */ + Wpending = 8, /* can write */ +}; + +enum { + None, + Flushing, + Flushed, +}; + +struct p9_req; + +typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a); +struct p9_req { + spinlock_t lock; /* protect request structure */ + int tag; + 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_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; + struct p9_idpool *tagpool; + int err; + wait_queue_head_t equeue; + struct list_head req_list; + struct list_head unsent_req_list; + struct p9_fcall *rcall; + int rpos; + char *rbuf; + int wpos; + int wsize; + char *wbuf; + wait_queue_t poll_wait[MAXPOLLWADDR]; + wait_queue_head_t *poll_waddr[MAXPOLLWADDR]; + poll_table pt; + struct work_struct rq; + struct work_struct wq; + unsigned long wsched; +}; + +struct p9_mux_poll_task { + struct task_struct *task; + struct list_head mux_list; + int muxnum; +}; + +struct p9_mux_rpc { + struct p9_conn *m; + int err; + struct p9_fcall *tcall; + struct p9_fcall *rcall; + 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_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 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 void p9_conn_destroy(struct p9_conn *); +static unsigned int p9_fd_poll(struct p9_trans *trans, + 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 int p9_mux_global_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; + } + + return 0; +} + +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); +} + +/** + * p9_mux_calc_poll_procs - calculates the number of polling procs + * 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) +{ + int i; + struct p9_mux_poll_task *vpt; + + mutex_lock(&p9_mux_task_lock); + vpt = m->poll_task; + list_del(&m->mux_list); + for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { + if (m->poll_waddr[i] != NULL) { + remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]); + m->poll_waddr[i] = NULL; + } + } + vpt->muxnum--; + if (!vpt->muxnum) { + P9_DPRINTK(P9_DEBUG_MUX, "destroy proc %p\n", vpt); + kthread_stop(vpt->task); + vpt->task = NULL; + p9_mux_poll_task_num--; + } + p9_mux_num--; + mutex_unlock(&p9_mux_task_lock); +} + +/** + * p9_conn_create - allocate and initialize the per-session mux data + * Creates the polling task if this is the first session. + * + * @trans - transport structure + * @msize - maximum message size + * @extended - extended flag + */ +static struct p9_conn *p9_conn_create(struct p9_trans *trans) +{ + int i, n; + struct p9_conn *m, *mtmp; + + P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans, + trans->msize); + m = kmalloc(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->tagpool = p9_idpool_create(); + if (IS_ERR(m->tagpool)) { + mtmp = ERR_PTR(-ENOMEM); + kfree(m); + return mtmp; + } + + m->err = 0; + init_waitqueue_head(&m->equeue); + INIT_LIST_HEAD(&m->req_list); + INIT_LIST_HEAD(&m->unsent_req_list); + m->rcall = NULL; + m->rpos = 0; + m->rbuf = NULL; + m->wpos = m->wsize = 0; + m->wbuf = NULL; + INIT_WORK(&m->rq, p9_read_work); + INIT_WORK(&m->wq, p9_write_work); + m->wsched = 0; + memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); + m->poll_task = NULL; + n = p9_mux_poll_start(m); + if (n) { + kfree(m); + return ERR_PTR(n); + } + + n = p9_fd_poll(trans, &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_waddr); i++) { + if (IS_ERR(m->poll_waddr[i])) { + p9_mux_poll_stop(m); + mtmp = (void *)m->poll_waddr; /* the error code */ + kfree(m); + m = mtmp; + break; + } + } + + return m; +} + +/** + * p9_mux_destroy - cancels all pending requests and frees mux resources + */ +static void p9_conn_destroy(struct p9_conn *m) +{ + P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m, + m->mux_list.prev, m->mux_list.next); + p9_conn_cancel(m, -ECONNRESET); + + if (!list_empty(&m->req_list)) { + /* wait until all processes waiting on this session exit */ + P9_DPRINTK(P9_DEBUG_MUX, + "mux %p waiting for empty request queue\n", m); + wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000); + P9_DPRINTK(P9_DEBUG_MUX, "mux %p request queue empty: %d\n", m, + list_empty(&m->req_list)); + } + + p9_mux_poll_stop(m); + m->trans = NULL; + p9_idpool_destroy(m->tagpool); + kfree(m); +} + +/** + * p9_pollwait - 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) +{ + 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) + break; + + if (i >= ARRAY_SIZE(m->poll_waddr)) { + 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); + return; + } + + init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task); + add_wait_queue(wait_address, &m->poll_wait[i]); +} + +/** + * p9_poll_mux - polls a mux and schedules read or write works if necessary + */ +static void p9_poll_mux(struct p9_conn *m) +{ + int n; + + if (m->err < 0) + return; + + n = p9_fd_poll(m->trans, 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 - polls all v9fs transports for new events and queues + * the appropriate work to the work queue + */ +static int p9_poll_proc(void *a) +{ + struct p9_conn *m, *mtmp; + struct p9_mux_poll_task *vpt; + + vpt = a; + P9_DPRINTK(P9_DEBUG_MUX, "start %p %p\n", current, vpt); + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + + list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) { + p9_poll_mux(m); + } + + P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n"); + schedule_timeout(SCHED_TIMEOUT * HZ); + } + + __set_current_state(TASK_RUNNING); + P9_DPRINTK(P9_DEBUG_MUX, "finish\n"); + return 0; +} + +/** + * p9_write_work - called when a transport can send some data + */ +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->trans, 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->trans, 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 void process_request(struct p9_conn *m, struct p9_req *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; + + P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len, + ename->str); + + if (m->extended) + req->err = -ecode; + + if (!req->err) { + req->err = p9_errstr2errno(ename->str, ename->len); + + /* string match failed */ + if (!req->err) { + PRINT_FCALL_ERROR("unknown error", req->rcall); + req->err = -ESERVERFAULT; + } + } + } else if (req->tcall && req->rcall->id != req->tcall->id + 1) { + P9_DPRINTK(P9_DEBUG_ERROR, + "fcall mismatch: expected %d, got %d\n", + req->tcall->id + 1, req->rcall->id); + if (!req->err) + req->err = -EIO; + } +} + +/** + * p9_read_work - called when there is some data to be read from a transport + */ +static void p9_read_work(struct work_struct *work) +{ + int n, err; + struct p9_conn *m; + struct p9_req *req, *rptr, *rreq; + struct p9_fcall *rcall; + char *rbuf; + + m = container_of(work, struct p9_conn, rq); + + if (m->err < 0) + return; + + rcall = NULL; + P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); + + if (!m->rcall) { + m->rcall = + kmalloc(sizeof(struct p9_fcall) + m->msize, GFP_KERNEL); + if (!m->rcall) { + err = -ENOMEM; + goto error; + } + + m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall); + m->rpos = 0; + } + + clear_bit(Rpending, &m->wsched); + err = p9_fd_read(m->trans, 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); + return; + } + + if (err <= 0) + goto error; + + m->rpos += err; + while (m->rpos > 4) { + n = le32_to_cpu(*(__le32 *) m->rbuf); + if (n >= m->msize) { + P9_DPRINTK(P9_DEBUG_ERROR, + "requested packet size too big: %d\n", n); + err = -EIO; + goto error; + } + + if (m->rpos < n) + break; + + err = + p9_deserialize_fcall(m->rbuf, n, m->rcall, m->extended); + if (err < 0) + goto error; + +#ifdef CONFIG_NET_9P_DEBUG + if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { + char buf[150]; + + p9_printfcall(buf, sizeof(buf), m->rcall, + m->extended); + 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->msize, + GFP_KERNEL); + if (!m->rcall) { + err = -ENOMEM; + goto error; + } + + m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall); + memmove(m->rbuf, rbuf + n, m->rpos - n); + m->rpos -= n; + } else { + m->rcall = NULL; + m->rbuf = NULL; + m->rpos = 0; + } + + P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, + rcall->id, rcall->tag); + + req = NULL; + spin_lock(&m->lock); + list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { + if (rreq->tag == rcall->tag) { + req = rreq; + if (req->flush != Flushing) + list_del(&req->req_list); + break; + } + } + spin_unlock(&m->lock); + + if (req) { + req->rcall = rcall; + process_request(m, req); + + if (req->flush != Flushing) { + if (req->cb) + (*req->cb) (req, req->cba); + else + kfree(req->rcall); + + wake_up(&m->equeue); + } + } else { + if (err >= 0 && rcall->id != P9_RFLUSH) + P9_DPRINTK(P9_DEBUG_ERROR, + "unexpected response mux %p id %d tag %d\n", + m, rcall->id, rcall->tag); + kfree(rcall); + } + } + + if (!list_empty(&m->req_list)) { + if (test_and_clear_bit(Rpending, &m->wsched)) + n = POLLIN; + else + n = p9_fd_poll(m->trans, NULL); + + if (n & POLLIN) { + P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m); + queue_work(p9_mux_wq, &m->rq); + } else + clear_bit(Rworksched, &m->wsched); + } else + clear_bit(Rworksched, &m->wsched); + + return; + +error: + p9_conn_cancel(m, err); + clear_bit(Rworksched, &m->wsched); +} + +/** + * p9_send_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. + * + * @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) +{ + int n; + struct p9_req *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); + + if (tc->id == P9_TVERSION) + n = P9_NOTAG; + else + n = p9_mux_get_tag(m); + + if (n < 0) + return ERR_PTR(-ENOMEM); + + p9_set_tag(tc, n); + +#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->extended); + printk(KERN_NOTICE "<<< %p %s\n", m, buf); + } +#endif + + spin_lock_init(&req->lock); + req->tag = n; + req->tcall = tc; + req->rcall = NULL; + req->err = 0; + req->cb = cb; + req->cba = cba; + req->flush = None; + + spin_lock(&m->lock); + list_add_tail(&req->req_list, &m->unsent_req_list); + spin_unlock(&m->lock); + + if (test_and_clear_bit(Wpending, &m->wsched)) + n = POLLOUT; + else + n = p9_fd_poll(m->trans, NULL); + + if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched)) + queue_work(p9_mux_wq, &m->wq); + + 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) +{ + p9_conn_req_callback cb; + 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); + cb = NULL; + 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); + + wake_up(&m->equeue); + } + + 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) +{ + struct p9_fcall *fc; + struct p9_req *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); + P9_DPRINTK(P9_DEBUG_MUX, + "mux %p req %p response already received\n", m, req); + return 0; + } + + req->flush = Flushing; + spin_unlock(&req->lock); + + spin_lock(&m->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); + if (req->cb) + (*req->cb) (req, req->cba); + return 0; + } + } + spin_unlock(&m->lock); + + clear_thread_flag(TIF_SIGPENDING); + fc = p9_create_tflush(req->tag); + p9_send_request(m, fc, p9_mux_flush_cb, m); + return 1; +} + +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; + + if (req->flush != None && !req->err) + r->err = -ERESTARTSYS; + + wake_up(&r->wqueue); +} + +/** + * p9_fd_rpc- sends 9P request and waits until a response is available. + * The function can be interrupted. + * @m: mux data + * @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) +{ + struct p9_trans_fd *p = t->priv; + struct p9_conn *m = p->conn; + 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; + + sigpending = 0; + if (signal_pending(current)) { + sigpending = 1; + clear_thread_flag(TIF_SIGPENDING); + } + + req = p9_send_request(m, tc, p9_conn_rpc_cb, &r); + 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; + + if (err == -ERESTARTSYS && m->trans->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(r.wqueue, + r.rcall || r.err); + } while (!r.rcall && !r.err && err == -ERESTARTSYS && + m->trans->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 = r.rcall; + else + kfree(r.rcall); + + p9_mux_free_request(m, req); + if (err > 0) + err = -EIO; + + 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 + * @cba: 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); + } + + wake_up(&m->equeue); +} + /** * v9fs_parse_options - parse mount options into session structure * @options: options string passed from mount @@ -268,7 +1294,7 @@ end: } /** - * p9_sock_close - shutdown socket + * p9_fd_close - shutdown socket * @trans: private socket structure * */ @@ -284,6 +1310,8 @@ static void p9_fd_close(struct p9_trans *trans) if (!ts) return; + p9_conn_destroy(ts->conn); + trans->status = Disconnected; if (ts->rd) fput(ts->rd); @@ -292,13 +1320,15 @@ static void p9_fd_close(struct p9_trans *trans) kfree(ts); } -static struct p9_trans *p9_trans_create_tcp(const char *addr, char *args) +static struct p9_trans * +p9_trans_create_tcp(const char *addr, char *args, int msize, unsigned char dotu) { int err; struct p9_trans *trans; struct socket *csocket; struct sockaddr_in sin_server; struct p9_fd_opts opts; + struct p9_trans_fd *p; parse_opts(args, &opts); @@ -306,11 +1336,10 @@ static struct p9_trans *p9_trans_create_tcp(const char *addr, char *args) trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); if (!trans) return ERR_PTR(-ENOMEM); - - trans->write = p9_fd_write; - trans->read = p9_fd_read; + trans->msize = msize; + trans->extended = dotu; + trans->rpc = p9_fd_rpc; trans->close = p9_fd_close; - trans->poll = p9_fd_poll; sin_server.sin_family = AF_INET; sin_server.sin_addr.s_addr = in_aton(addr); @@ -337,6 +1366,14 @@ static struct p9_trans *p9_trans_create_tcp(const char *addr, char *args) if (err < 0) goto error; + p = (struct p9_trans_fd *) trans->priv; + p->conn = p9_conn_create(trans); + if (IS_ERR(p->conn)) { + err = PTR_ERR(p->conn); + p->conn = NULL; + goto error; + } + return trans; error: @@ -347,22 +1384,23 @@ error: return ERR_PTR(err); } -static struct p9_trans *p9_trans_create_unix(const char *addr, char *args) +static struct p9_trans * +p9_trans_create_unix(const char *addr, char *args, int msize, + unsigned char dotu) { int err; struct socket *csocket; struct sockaddr_un sun_server; struct p9_trans *trans; + struct p9_trans_fd *p; csocket = NULL; trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); if (!trans) return ERR_PTR(-ENOMEM); - trans->write = p9_fd_write; - trans->read = p9_fd_read; + trans->rpc = p9_fd_rpc; trans->close = p9_fd_close; - trans->poll = p9_fd_poll; if (strlen(addr) > UNIX_PATH_MAX) { P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n", @@ -387,6 +1425,16 @@ static struct p9_trans *p9_trans_create_unix(const char *addr, char *args) if (err < 0) goto error; + trans->msize = msize; + trans->extended = dotu; + p = (struct p9_trans_fd *) trans->priv; + p->conn = p9_conn_create(trans); + if (IS_ERR(p->conn)) { + err = PTR_ERR(p->conn); + p->conn = NULL; + goto error; + } + return trans; error: @@ -397,11 +1445,14 @@ error: return ERR_PTR(err); } -static struct p9_trans *p9_trans_create_fd(const char *name, char *args) +static struct p9_trans * +p9_trans_create_fd(const char *name, char *args, int msize, + unsigned char extended) { int err; struct p9_trans *trans; struct p9_fd_opts opts; + struct p9_trans_fd *p; parse_opts(args, &opts); @@ -414,15 +1465,23 @@ static struct p9_trans *p9_trans_create_fd(const char *name, char *args) if (!trans) return ERR_PTR(-ENOMEM); - trans->write = p9_fd_write; - trans->read = p9_fd_read; + trans->rpc = p9_fd_rpc; trans->close = p9_fd_close; - trans->poll = p9_fd_poll; err = p9_fd_open(trans, 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); + if (IS_ERR(p->conn)) { + err = PTR_ERR(p->conn); + p->conn = NULL; + goto error; + } + return trans; error: @@ -453,6 +1512,12 @@ static struct p9_trans_module p9_fd_trans = { static int __init p9_trans_fd_init(void) { + int ret = p9_mux_global_init(); + if (ret) { + printk(KERN_WARNING "9p: starting mux failed\n"); + return ret; + } + v9fs_register_trans(&p9_tcp_trans); v9fs_register_trans(&p9_unix_trans); v9fs_register_trans(&p9_fd_trans); @@ -460,13 +1525,7 @@ static int __init p9_trans_fd_init(void) return 1; } -static void __exit p9_trans_fd_exit(void) { - printk(KERN_ERR "Removal of 9p transports not implemented\n"); - BUG(); -} - module_init(p9_trans_fd_init); -module_exit(p9_trans_fd_exit); MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>"); MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>"); diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 42eea5fe2628..0117b9fb8480 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -1,17 +1,8 @@ /* * The Guest 9p transport driver * - * This is a trivial pipe-based transport driver based on the lguest console - * code: we use lguest's DMA mechanism to send bytes out, and register a - * DMA buffer to receive bytes in. It is assumed to be present and available - * from the very beginning of boot. - * - * This may be have been done by just instaniating another HVC console, - * but HVC's blocksize of 16 bytes is annoying and painful to performance. - * - * A more efficient transport could be built based on the virtio block driver - * but it requires some changes in the 9p transport model (which are in - * progress) + * This is a block based transport driver based on the lguest block driver + * code. * */ /* @@ -55,11 +46,25 @@ #include <linux/virtio.h> #include <linux/virtio_9p.h> +#define VIRTQUEUE_NUM 128 + /* a single mutex to manage channel initialization and attachment */ static DECLARE_MUTEX(virtio_9p_lock); /* global which tracks highest initialized channel */ static int chan_index; +#define P9_INIT_MAXTAG 16 + +#define REQ_STATUS_IDLE 0 +#define REQ_STATUS_SENT 1 +#define REQ_STATUS_RCVD 2 +#define REQ_STATUS_FLSH 3 + +struct p9_req_t { + int status; + wait_queue_head_t *wq; +}; + /* We keep all per-channel information in a structure. * This structure is allocated within the devices dev->mem space. * A pointer to the structure will get put in the transport private. @@ -68,146 +73,198 @@ static struct virtio_chan { bool initialized; /* channel is initialized */ bool inuse; /* channel is in use */ - struct virtqueue *in_vq, *out_vq; + spinlock_t lock; + struct virtio_device *vdev; + struct virtqueue *vq; - /* This is our input buffer, and how much data is left in it. */ - unsigned int in_len; - char *in, *inbuf; + struct p9_idpool *tagpool; + struct p9_req_t *reqs; + int max_tag; - wait_queue_head_t wq; /* waitq for buffer */ + /* Scatterlist: can be too big for stack. */ + struct scatterlist sg[VIRTQUEUE_NUM]; } channels[MAX_9P_CHAN]; +/* Lookup requests by tag */ +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_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) { return PAGE_SIZE - ((unsigned long)data % PAGE_SIZE); } -static int p9_virtio_write(struct p9_trans *trans, void *buf, int count) +static void p9_virtio_close(struct p9_trans *trans) { - struct virtio_chan *chan = (struct virtio_chan *) trans->priv; - struct virtqueue *out_vq = chan->out_vq; - struct scatterlist sg[1]; - unsigned int len; + struct virtio_chan *chan = trans->priv; + int count; + unsigned int flags; - P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio write (%d)\n", count); + 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); - /* keep it simple - make sure we don't overflow a page */ - if (rest_of_page(buf) < count) - count = rest_of_page(buf); + down(&virtio_9p_lock); + chan->inuse = false; + up(&virtio_9p_lock); - sg_init_one(sg, buf, count); + kfree(trans); +} - /* add_buf wants a token to identify this buffer: we hand it any - * non-NULL pointer, since there's only ever one buffer. */ - if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, (void *)1) == 0) { - /* Tell Host to go! */ - out_vq->vq_ops->kick(out_vq); - /* Chill out until it's done with the buffer. */ - while (!out_vq->vq_ops->get_buf(out_vq, &len)) - cpu_relax(); +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); + while ((rc = chan->vq->vq_ops->get_buf(chan->vq, &len)) != NULL) { + req = p9_lookup_tag(chan, rc->tag); + req->status = REQ_STATUS_RCVD; + wake_up(req->wq); } - - P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio wrote (%d)\n", count); - - /* We're expected to return the amount of data we wrote: all of it. */ - return count; + /* In case queue is stopped waiting for more buffers. */ + spin_unlock_irqrestore(&chan->lock, flags); } -/* Create a scatter-gather list representing our input buffer and put it in the - * queue. */ -static void add_inbuf(struct virtio_chan *chan) +static int +pack_sg_list(struct scatterlist *sg, int start, int limit, char *data, + int count) { - struct scatterlist sg[1]; - - sg_init_one(sg, chan->inbuf, PAGE_SIZE); + int s; + int index = start; + + while (count) { + s = rest_of_page(data); + if (s > count) + s = count; + sg_set_buf(&sg[index++], data, s); + count -= s; + data += s; + if (index > limit) + BUG(); + } - /* We should always be able to add one buffer to an empty queue. */ - if (chan->in_vq->vq_ops->add_buf(chan->in_vq, sg, 0, 1, chan->inbuf)) - BUG(); - chan->in_vq->vq_ops->kick(chan->in_vq); + return index-start; } -static int p9_virtio_read(struct p9_trans *trans, void *buf, int count) +static int +p9_virtio_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc) { - struct virtio_chan *chan = (struct virtio_chan *) trans->priv; - struct virtqueue *in_vq = chan->in_vq; - - P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio read (%d)\n", count); + int in, out; + int n, err, size; + struct virtio_chan *chan = t->priv; + char *rdata; + struct p9_req_t *req; + unsigned long flags; + + if (*rc == NULL) { + *rc = kmalloc(sizeof(struct p9_fcall) + t->msize, GFP_KERNEL); + if (!*rc) + return -ENOMEM; + } - /* If we don't have an input queue yet, we can't get input. */ - BUG_ON(!in_vq); + rdata = (char *)*rc+sizeof(struct p9_fcall); - /* No buffer? Try to get one. */ - if (!chan->in_len) { - chan->in = in_vq->vq_ops->get_buf(in_vq, &chan->in_len); - if (!chan->in) - return 0; + n = P9_NOTAG; + if (tc->id != P9_TVERSION) { + n = p9_idpool_get(chan->tagpool); + if (n < 0) + return -ENOMEM; } - /* You want more than we have to give? Well, try wanting less! */ - if (chan->in_len < count) - count = chan->in_len; + spin_lock_irqsave(&chan->lock, flags); + req = p9_lookup_tag(chan, n); + spin_unlock_irqrestore(&chan->lock, flags); - /* Copy across to their buffer and increment offset. */ - memcpy(buf, chan->in, count); - chan->in += count; - chan->in_len -= count; + p9_set_tag(tc, n); - /* Finished? Re-register buffer so Host will use it again. */ - if (chan->in_len == 0) - add_inbuf(chan); + P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio rpc tag %d\n", n); - P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio finished read (%d)\n", - count); + 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); - return count; -} + req->status = REQ_STATUS_SENT; -/* The poll function is used by 9p transports to determine if there - * is there is activity available on a particular channel. In our case - * we use it to wait for a callback from the input routines. - */ -static unsigned int -p9_virtio_poll(struct p9_trans *trans, struct poll_table_struct *pt) -{ - struct virtio_chan *chan = (struct virtio_chan *)trans->priv; - struct virtqueue *in_vq = chan->in_vq; - int ret = POLLOUT; /* we can always handle more output */ + if (chan->vq->vq_ops->add_buf(chan->vq, chan->sg, out, in, tc)) { + P9_DPRINTK(P9_DEBUG_TRANS, + "9p debug: virtio rpc add_buf returned failure"); + return -EIO; + } - poll_wait(NULL, &chan->wq, pt); + chan->vq->vq_ops->kick(chan->vq); - /* No buffer? Try to get one. */ - if (!chan->in_len) - chan->in = in_vq->vq_ops->get_buf(in_vq, &chan->in_len); + wait_event(*req->wq, req->status == REQ_STATUS_RCVD); - if (chan->in_len) - ret |= POLLIN; + size = le32_to_cpu(*(__le32 *) rdata); - return ret; -} + err = p9_deserialize_fcall(rdata, size, *rc, t->extended); + if (err < 0) { + P9_DPRINTK(P9_DEBUG_TRANS, + "9p debug: virtio rpc deserialize returned %d\n", err); + return err; + } -static void p9_virtio_close(struct p9_trans *trans) -{ - struct virtio_chan *chan = trans->priv; +#ifdef CONFIG_NET_9P_DEBUG + if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { + char buf[150]; - down(&virtio_9p_lock); - chan->inuse = false; - up(&virtio_9p_lock); + p9_printfcall(buf, sizeof(buf), *rc, t->extended); + printk(KERN_NOTICE ">>> %p %s\n", t, buf); + } +#endif - kfree(trans); -} + if (n != P9_NOTAG && p9_idpool_check(n, chan->tagpool)) + p9_idpool_put(n, chan->tagpool); -static void p9_virtio_intr(struct virtqueue *q) -{ - struct virtio_chan *chan = q->vdev->priv; + req->status = REQ_STATUS_IDLE; - P9_DPRINTK(P9_DEBUG_TRANS, "9p poll_wakeup: %p\n", &chan->wq); - wake_up_interruptible(&chan->wq); + return 0; } -static int p9_virtio_probe(struct virtio_device *dev) +static int p9_virtio_probe(struct virtio_device *vdev) { int err; struct virtio_chan *chan; @@ -221,44 +278,29 @@ static int p9_virtio_probe(struct virtio_device *dev) if (chan_index > MAX_9P_CHAN) { printk(KERN_ERR "9p: virtio: Maximum channels exceeded\n"); BUG(); - } - - chan->vdev = dev; - - /* This is the scratch page we use to receive console input */ - chan->inbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!chan->inbuf) { err = -ENOMEM; goto fail; } - /* Find the input queue. */ - dev->priv = chan; - chan->in_vq = dev->config->find_vq(dev, 0, p9_virtio_intr); - if (IS_ERR(chan->in_vq)) { - err = PTR_ERR(chan->in_vq); - goto free; - } + chan->vdev = vdev; - chan->out_vq = dev->config->find_vq(dev, 1, NULL); - if (IS_ERR(chan->out_vq)) { - err = PTR_ERR(chan->out_vq); - goto free_in_vq; + /* We expect one virtqueue, for requests. */ + chan->vq = vdev->config->find_vq(vdev, 0, req_done); + if (IS_ERR(chan->vq)) { + err = PTR_ERR(chan->vq); + goto out_free_vq; } + chan->vq->vdev->priv = chan; + spin_lock_init(&chan->lock); - init_waitqueue_head(&chan->wq); + sg_init_table(chan->sg, VIRTQUEUE_NUM); - /* Register the input buffer the first time. */ - add_inbuf(chan); chan->inuse = false; chan->initialized = true; - return 0; -free_in_vq: - dev->config->del_vq(chan->in_vq); -free: - kfree(chan->inbuf); +out_free_vq: + vdev->config->del_vq(chan->vq); fail: down(&virtio_9p_lock); chan_index--; @@ -271,11 +313,13 @@ fail: * alternate channels by matching devname versus a virtio_config entry. * We use a simple reference count mechanism to ensure that only a single * mount has a channel open at a time. */ -static struct p9_trans *p9_virtio_create(const char *devname, char *args) +static struct p9_trans * +p9_virtio_create(const char *devname, char *args, int msize, + unsigned char extended) { struct p9_trans *trans; - int index = 0; struct virtio_chan *chan = channels; + int index = 0; down(&virtio_9p_lock); while (index < MAX_9P_CHAN) { @@ -290,25 +334,45 @@ static struct p9_trans *p9_virtio_create(const char *devname, char *args) up(&virtio_9p_lock); if (index >= MAX_9P_CHAN) { - printk(KERN_ERR "9p: virtio: couldn't find a free channel\n"); - return NULL; + printk(KERN_ERR "9p: no channels available\n"); + return ERR_PTR(-ENODEV); } + chan->tagpool = p9_idpool_create(); + if (IS_ERR(chan->tagpool)) { + printk(KERN_ERR "9p: couldn't allocate tagpool\n"); + return ERR_PTR(-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->write = p9_virtio_write; - trans->read = p9_virtio_read; + trans->extended = extended; + trans->msize = msize; trans->close = p9_virtio_close; - trans->poll = p9_virtio_poll; + trans->rpc = p9_virtio_rpc; trans->priv = chan; return trans; } +static void p9_virtio_remove(struct virtio_device *vdev) +{ + struct virtio_chan *chan = vdev->priv; + + BUG_ON(chan->inuse); + + if (chan->initialized) { + vdev->config->del_vq(chan->vq); + chan->initialized = false; + } +} + #define VIRTIO_ID_9P 9 static struct virtio_device_id id_table[] = { @@ -322,12 +386,13 @@ static struct virtio_driver p9_virtio_drv = { .driver.owner = THIS_MODULE, .id_table = id_table, .probe = p9_virtio_probe, + .remove = p9_virtio_remove, }; static struct p9_trans_module p9_virtio_trans = { .name = "virtio", .create = p9_virtio_create, - .maxsize = PAGE_SIZE, + .maxsize = PAGE_SIZE*16, .def = 0, }; @@ -343,7 +408,13 @@ static int __init p9_virtio_init(void) return register_virtio_driver(&p9_virtio_drv); } +static void __exit p9_virtio_cleanup(void) +{ + unregister_virtio_driver(&p9_virtio_drv); +} + module_init(p9_virtio_init); +module_exit(p9_virtio_cleanup); MODULE_DEVICE_TABLE(virtio, id_table); MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>"); diff --git a/net/9p/util.c b/net/9p/util.c index 22077b79395d..ef7215565d88 100644 --- a/net/9p/util.c +++ b/net/9p/util.c @@ -33,7 +33,7 @@ #include <net/9p/9p.h> struct p9_idpool { - struct semaphore lock; + spinlock_t lock; struct idr pool; }; @@ -45,7 +45,7 @@ struct p9_idpool *p9_idpool_create(void) if (!p) return ERR_PTR(-ENOMEM); - init_MUTEX(&p->lock); + spin_lock_init(&p->lock); idr_init(&p->pool); return p; @@ -71,19 +71,17 @@ int p9_idpool_get(struct p9_idpool *p) { int i = 0; int error; + unsigned int flags; retry: if (idr_pre_get(&p->pool, GFP_KERNEL) == 0) return 0; - if (down_interruptible(&p->lock) == -EINTR) { - P9_EPRINTK(KERN_WARNING, "Interrupted while locking\n"); - return -1; - } + spin_lock_irqsave(&p->lock, flags); /* no need to store exactly p, we just need something non-null */ error = idr_get_new(&p->pool, p, &i); - up(&p->lock); + spin_unlock_irqrestore(&p->lock, flags); if (error == -EAGAIN) goto retry; @@ -104,12 +102,10 @@ EXPORT_SYMBOL(p9_idpool_get); void p9_idpool_put(int id, struct p9_idpool *p) { - if (down_interruptible(&p->lock) == -EINTR) { - P9_EPRINTK(KERN_WARNING, "Interrupted while locking\n"); - return; - } + unsigned int flags; + spin_lock_irqsave(&p->lock, flags); idr_remove(&p->pool, id); - up(&p->lock); + spin_unlock_irqrestore(&p->lock, flags); } EXPORT_SYMBOL(p9_idpool_put); diff --git a/net/Kconfig b/net/Kconfig index b6a5d454f2ff..6627c6ae5db6 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -30,7 +30,7 @@ menu "Networking options" config NET_NS bool "Network namespace support" default n - depends on EXPERIMENTAL && !SYSFS + depends on EXPERIMENTAL && !SYSFS && NAMESPACES help Allow user space to create what appear to be multiple instances of the network stack. diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 8fc64e3150a2..48bfcc741f25 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -510,11 +510,7 @@ ax25_cb *ax25_create_cb(void) skb_queue_head_init(&ax25->ack_queue); skb_queue_head_init(&ax25->reseq_queue); - init_timer(&ax25->timer); - init_timer(&ax25->t1timer); - init_timer(&ax25->t2timer); - init_timer(&ax25->t3timer); - init_timer(&ax25->idletimer); + ax25_setup_timers(ax25); ax25_fillin_cb(ax25, NULL); @@ -1928,12 +1924,10 @@ static int ax25_info_show(struct seq_file *seq, void *v) ax25->paclen); if (ax25->sk != NULL) { - bh_lock_sock(ax25->sk); - seq_printf(seq," %d %d %ld\n", + seq_printf(seq, " %d %d %lu\n", atomic_read(&ax25->sk->sk_wmem_alloc), atomic_read(&ax25->sk->sk_rmem_alloc), - ax25->sk->sk_socket != NULL ? SOCK_INODE(ax25->sk->sk_socket)->i_ino : 0L); - bh_unlock_sock(ax25->sk); + sock_i_ino(ax25->sk)); } else { seq_puts(seq, " * * *\n"); } diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c index 528c874d9828..a7a0e0c9698b 100644 --- a/net/ax25/ax25_dev.c +++ b/net/ax25/ax25_dev.c @@ -82,7 +82,7 @@ void ax25_dev_device_up(struct net_device *dev) ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT; #if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER) - init_timer(&ax25_dev->dama.slave_timer); + ax25_ds_setup_timer(ax25_dev); #endif spin_lock_bh(&ax25_dev_lock); diff --git a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c index c4e3b025d21c..2ce79df00680 100644 --- a/net/ax25/ax25_ds_timer.c +++ b/net/ax25/ax25_ds_timer.c @@ -40,13 +40,10 @@ static void ax25_ds_timeout(unsigned long); * 1/10th of a second. */ -static void ax25_ds_add_timer(ax25_dev *ax25_dev) +void ax25_ds_setup_timer(ax25_dev *ax25_dev) { - struct timer_list *t = &ax25_dev->dama.slave_timer; - t->data = (unsigned long) ax25_dev; - t->function = &ax25_ds_timeout; - t->expires = jiffies + HZ; - add_timer(t); + setup_timer(&ax25_dev->dama.slave_timer, ax25_ds_timeout, + (unsigned long)ax25_dev); } void ax25_ds_del_timer(ax25_dev *ax25_dev) @@ -60,10 +57,9 @@ void ax25_ds_set_timer(ax25_dev *ax25_dev) if (ax25_dev == NULL) /* paranoia */ return; - del_timer(&ax25_dev->dama.slave_timer); ax25_dev->dama.slave_timeout = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_DS_TIMEOUT]) / 10; - ax25_ds_add_timer(ax25_dev); + mod_timer(&ax25_dev->dama.slave_timer, jiffies + HZ); } /* diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c index 38c7f3087ec3..8672cd84fdf9 100644 --- a/net/ax25/ax25_route.c +++ b/net/ax25/ax25_route.c @@ -45,7 +45,7 @@ void ax25_rt_device_down(struct net_device *dev) { ax25_route *s, *t, *ax25_rt; - write_lock(&ax25_route_lock); + write_lock_bh(&ax25_route_lock); ax25_rt = ax25_route_list; while (ax25_rt != NULL) { s = ax25_rt; @@ -68,7 +68,7 @@ void ax25_rt_device_down(struct net_device *dev) } } } - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); } static int __must_check ax25_rt_add(struct ax25_routes_struct *route) @@ -82,7 +82,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) if (route->digi_count > AX25_MAX_DIGIS) return -EINVAL; - write_lock(&ax25_route_lock); + write_lock_bh(&ax25_route_lock); ax25_rt = ax25_route_list; while (ax25_rt != NULL) { @@ -92,7 +92,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) ax25_rt->digipeat = NULL; if (route->digi_count != 0) { if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return -ENOMEM; } ax25_rt->digipeat->lastrepeat = -1; @@ -102,14 +102,14 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) ax25_rt->digipeat->calls[i] = route->digi_addr[i]; } } - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return 0; } ax25_rt = ax25_rt->next; } if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) { - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return -ENOMEM; } @@ -120,7 +120,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) ax25_rt->ip_mode = ' '; if (route->digi_count != 0) { if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); kfree(ax25_rt); return -ENOMEM; } @@ -133,7 +133,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) } ax25_rt->next = ax25_route_list; ax25_route_list = ax25_rt; - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return 0; } @@ -152,7 +152,7 @@ static int ax25_rt_del(struct ax25_routes_struct *route) if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL) return -EINVAL; - write_lock(&ax25_route_lock); + write_lock_bh(&ax25_route_lock); ax25_rt = ax25_route_list; while (ax25_rt != NULL) { @@ -174,7 +174,7 @@ static int ax25_rt_del(struct ax25_routes_struct *route) } } } - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return 0; } @@ -188,7 +188,7 @@ static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option) if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL) return -EINVAL; - write_lock(&ax25_route_lock); + write_lock_bh(&ax25_route_lock); ax25_rt = ax25_route_list; while (ax25_rt != NULL) { @@ -216,7 +216,7 @@ static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option) } out: - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return err; } @@ -492,7 +492,7 @@ void __exit ax25_rt_free(void) { ax25_route *s, *ax25_rt = ax25_route_list; - write_lock(&ax25_route_lock); + write_lock_bh(&ax25_route_lock); while (ax25_rt != NULL) { s = ax25_rt; ax25_rt = ax25_rt->next; @@ -500,5 +500,5 @@ void __exit ax25_rt_free(void) kfree(s->digipeat); kfree(s); } - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); } diff --git a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c index 72594867fab6..db29ea71e80a 100644 --- a/net/ax25/ax25_timer.c +++ b/net/ax25/ax25_timer.c @@ -40,63 +40,45 @@ static void ax25_t2timer_expiry(unsigned long); static void ax25_t3timer_expiry(unsigned long); static void ax25_idletimer_expiry(unsigned long); -void ax25_start_heartbeat(ax25_cb *ax25) +void ax25_setup_timers(ax25_cb *ax25) { - del_timer(&ax25->timer); - - ax25->timer.data = (unsigned long)ax25; - ax25->timer.function = &ax25_heartbeat_expiry; - ax25->timer.expires = jiffies + 5 * HZ; + setup_timer(&ax25->timer, ax25_heartbeat_expiry, (unsigned long)ax25); + setup_timer(&ax25->t1timer, ax25_t1timer_expiry, (unsigned long)ax25); + setup_timer(&ax25->t2timer, ax25_t2timer_expiry, (unsigned long)ax25); + setup_timer(&ax25->t3timer, ax25_t3timer_expiry, (unsigned long)ax25); + setup_timer(&ax25->idletimer, ax25_idletimer_expiry, + (unsigned long)ax25); +} - add_timer(&ax25->timer); +void ax25_start_heartbeat(ax25_cb *ax25) +{ + mod_timer(&ax25->timer, jiffies + 5 * HZ); } void ax25_start_t1timer(ax25_cb *ax25) { - del_timer(&ax25->t1timer); - - ax25->t1timer.data = (unsigned long)ax25; - ax25->t1timer.function = &ax25_t1timer_expiry; - ax25->t1timer.expires = jiffies + ax25->t1; - - add_timer(&ax25->t1timer); + mod_timer(&ax25->t1timer, jiffies + ax25->t1); } void ax25_start_t2timer(ax25_cb *ax25) { - del_timer(&ax25->t2timer); - - ax25->t2timer.data = (unsigned long)ax25; - ax25->t2timer.function = &ax25_t2timer_expiry; - ax25->t2timer.expires = jiffies + ax25->t2; - - add_timer(&ax25->t2timer); + mod_timer(&ax25->t2timer, jiffies + ax25->t2); } void ax25_start_t3timer(ax25_cb *ax25) { - del_timer(&ax25->t3timer); - - if (ax25->t3 > 0) { - ax25->t3timer.data = (unsigned long)ax25; - ax25->t3timer.function = &ax25_t3timer_expiry; - ax25->t3timer.expires = jiffies + ax25->t3; - - add_timer(&ax25->t3timer); - } + if (ax25->t3 > 0) + mod_timer(&ax25->t3timer, jiffies + ax25->t3); + else + del_timer(&ax25->t3timer); } void ax25_start_idletimer(ax25_cb *ax25) { - del_timer(&ax25->idletimer); - - if (ax25->idle > 0) { - ax25->idletimer.data = (unsigned long)ax25; - ax25->idletimer.function = &ax25_idletimer_expiry; - ax25->idletimer.expires = jiffies + ax25->idle; - - add_timer(&ax25->idletimer); - } + if (ax25->idle > 0) + mod_timer(&ax25->idletimer, jiffies + ax25->idle); + else + del_timer(&ax25->idletimer); } void ax25_stop_heartbeat(ax25_cb *ax25) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index d3e4e1877e6a..0c2c93735e93 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -465,7 +465,7 @@ int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb) return len; } -void fastcall __rfcomm_dlc_throttle(struct rfcomm_dlc *d) +void __rfcomm_dlc_throttle(struct rfcomm_dlc *d) { BT_DBG("dlc %p state %ld", d, d->state); @@ -476,7 +476,7 @@ void fastcall __rfcomm_dlc_throttle(struct rfcomm_dlc *d) rfcomm_schedule(RFCOMM_SCHED_TX); } -void fastcall __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) +void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) { BT_DBG("dlc %p state %ld", d, d->state); diff --git a/net/can/af_can.c b/net/can/af_can.c index 5158e886630f..36b9f22ed83a 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -118,7 +118,6 @@ static int can_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; struct can_proto *cp; - char module_name[sizeof("can-proto-000")]; int err = 0; sock->state = SS_UNCONNECTED; @@ -129,26 +128,21 @@ static int can_create(struct net *net, struct socket *sock, int protocol) if (net != &init_net) return -EAFNOSUPPORT; +#ifdef CONFIG_KMOD /* try to load protocol module, when CONFIG_KMOD is defined */ if (!proto_tab[protocol]) { - sprintf(module_name, "can-proto-%d", protocol); - err = request_module(module_name); + err = request_module("can-proto-%d", protocol); /* * In case of error we only print a message but don't * return the error code immediately. Below we will * return -EPROTONOSUPPORT */ - if (err == -ENOSYS) { - if (printk_ratelimit()) - printk(KERN_INFO "can: request_module(%s)" - " not implemented.\n", module_name); - } else if (err) { - if (printk_ratelimit()) - printk(KERN_ERR "can: request_module(%s)" - " failed.\n", module_name); - } + if (err && printk_ratelimit()) + printk(KERN_ERR "can: request_module " + "(can-proto-%d) failed.\n", protocol); } +#endif spin_lock(&proto_tab_lock); cp = proto_tab[protocol]; @@ -662,26 +656,26 @@ int can_proto_register(struct can_proto *cp) return -EINVAL; } + err = proto_register(cp->prot, 0); + if (err < 0) + return err; + spin_lock(&proto_tab_lock); if (proto_tab[proto]) { printk(KERN_ERR "can: protocol %d already registered\n", proto); err = -EBUSY; - goto errout; + } else { + proto_tab[proto] = cp; + + /* use generic ioctl function if not defined by module */ + if (!cp->ops->ioctl) + cp->ops->ioctl = can_ioctl; } + spin_unlock(&proto_tab_lock); - err = proto_register(cp->prot, 0); if (err < 0) - goto errout; - - proto_tab[proto] = cp; - - /* use generic ioctl function if the module doesn't bring its own */ - if (!cp->ops->ioctl) - cp->ops->ioctl = can_ioctl; - - errout: - spin_unlock(&proto_tab_lock); + proto_unregister(cp->prot); return err; } @@ -700,9 +694,10 @@ void can_proto_unregister(struct can_proto *cp) printk(KERN_ERR "BUG: can: protocol %d is not registered\n", proto); } - proto_unregister(cp->prot); proto_tab[proto] = NULL; spin_unlock(&proto_tab_lock); + + proto_unregister(cp->prot); } EXPORT_SYMBOL(can_proto_unregister); diff --git a/net/can/raw.c b/net/can/raw.c index aeefd1419d00..94cd7f27c444 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -98,7 +98,6 @@ static void raw_rcv(struct sk_buff *skb, void *data) struct sock *sk = (struct sock *)data; struct raw_sock *ro = raw_sk(sk); struct sockaddr_can *addr; - int error; if (!ro->recv_own_msgs) { /* check the received tx sock reference */ @@ -121,14 +120,12 @@ static void raw_rcv(struct sk_buff *skb, void *data) addr->can_family = AF_CAN; addr->can_ifindex = skb->dev->ifindex; - error = sock_queue_rcv_skb(sk, skb); - if (error < 0) + if (sock_queue_rcv_skb(sk, skb) < 0) kfree_skb(skb); } static int raw_enable_filters(struct net_device *dev, struct sock *sk, - struct can_filter *filter, - int count) + struct can_filter *filter, int count) { int err = 0; int i; @@ -163,8 +160,7 @@ static int raw_enable_errfilter(struct net_device *dev, struct sock *sk, } static void raw_disable_filters(struct net_device *dev, struct sock *sk, - struct can_filter *filter, - int count) + struct can_filter *filter, int count) { int i; @@ -353,7 +349,6 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len) /* filters set by default/setsockopt */ err = raw_enable_allfilters(dev, sk); dev_put(dev); - } else { ifindex = 0; @@ -466,7 +461,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, if (err) { if (count > 1) kfree(filter); - goto out_fil; } @@ -673,25 +667,25 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock, { struct sock *sk = sock->sk; struct sk_buff *skb; - int error = 0; + int err = 0; int noblock; noblock = flags & MSG_DONTWAIT; flags &= ~MSG_DONTWAIT; - skb = skb_recv_datagram(sk, flags, noblock, &error); + skb = skb_recv_datagram(sk, flags, noblock, &err); if (!skb) - return error; + return err; if (size < skb->len) msg->msg_flags |= MSG_TRUNC; else size = skb->len; - error = memcpy_toiovec(msg->msg_iov, skb->data, size); - if (error < 0) { + err = memcpy_toiovec(msg->msg_iov, skb->data, size); + if (err < 0) { skb_free_datagram(sk, skb); - return error; + return err; } sock_recv_timestamp(msg, sk, skb); diff --git a/net/core/dev.c b/net/core/dev.c index 9549417250bb..908f07c3bd7d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1071,8 +1071,6 @@ int dev_close(struct net_device *dev) */ call_netdevice_notifiers(NETDEV_GOING_DOWN, dev); - dev_deactivate(dev); - clear_bit(__LINK_STATE_START, &dev->state); /* Synchronize to scheduled poll. We cannot touch poll list, @@ -1083,6 +1081,8 @@ int dev_close(struct net_device *dev) */ smp_mb__after_clear_bit(); /* Commit netif_running(). */ + dev_deactivate(dev); + /* * Call the device specific close. This cannot fail. * Only if device is UP @@ -2143,7 +2143,7 @@ static int process_backlog(struct napi_struct *napi, int quota) * * The entry's receive function will be scheduled to run */ -void fastcall __napi_schedule(struct napi_struct *n) +void __napi_schedule(struct napi_struct *n) { unsigned long flags; @@ -3038,8 +3038,7 @@ int dev_unicast_sync(struct net_device *to, struct net_device *from) EXPORT_SYMBOL(dev_unicast_sync); /** - * dev_unicast_unsync - Remove synchronized addresses from the destination - * device + * dev_unicast_unsync - Remove synchronized addresses from the destination device * @to: destination device * @from: source device * diff --git a/net/core/flow.c b/net/core/flow.c index 46b38e06e0d7..a77531c139b7 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -30,8 +30,8 @@ struct flow_cache_entry { struct flow_cache_entry *next; u16 family; u8 dir; - struct flowi key; u32 genid; + struct flowi key; void *object; atomic_t *object_ref; }; @@ -52,7 +52,7 @@ struct flow_percpu_info { int hash_rnd_recalc; u32 hash_rnd; int count; -} ____cacheline_aligned; +}; static DEFINE_PER_CPU(struct flow_percpu_info, flow_hash_info) = { 0 }; #define flow_hash_rnd_recalc(cpu) \ @@ -346,7 +346,7 @@ static int __init flow_cache_init(void) flow_cachep = kmem_cache_create("flow_cache", sizeof(struct flow_cache_entry), - 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, + 0, SLAB_PANIC, NULL); flow_hash_shift = 10; flow_lwm = 2 * flow_hash_size; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index a16cf1ec5e5e..7bb6a9a1256d 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -834,18 +834,12 @@ static void neigh_timer_handler(unsigned long arg) } if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) { struct sk_buff *skb = skb_peek(&neigh->arp_queue); - /* keep skb alive even if arp_queue overflows */ - if (skb) - skb_get(skb); - write_unlock(&neigh->lock); + neigh->ops->solicit(neigh, skb); atomic_inc(&neigh->probes); - if (skb) - kfree_skb(skb); - } else { -out: - write_unlock(&neigh->lock); } +out: + write_unlock(&neigh->lock); if (notify) neigh_update_notify(neigh); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 61ac8d06292c..ecb02afd52dc 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -504,7 +504,7 @@ int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id, EXPORT_SYMBOL_GPL(rtnl_put_cacheinfo); -static void set_operstate(struct net_device *dev, unsigned char transition) +static int set_operstate(struct net_device *dev, unsigned char transition, bool send_notification) { unsigned char operstate = dev->operstate; @@ -527,8 +527,12 @@ static void set_operstate(struct net_device *dev, unsigned char transition) write_lock_bh(&dev_base_lock); dev->operstate = operstate; write_unlock_bh(&dev_base_lock); - netdev_state_change(dev); - } + + if (send_notification) + netdev_state_change(dev); + return 1; + } else + return 0; } static void copy_rtnl_link_stats(struct rtnl_link_stats *a, @@ -822,6 +826,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, if (tb[IFLA_BROADCAST]) { nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len); send_addr_notify = 1; + modified = 1; } if (ifm->ifi_flags || ifm->ifi_change) { @@ -834,16 +839,23 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, dev_change_flags(dev, flags); } - if (tb[IFLA_TXQLEN]) - dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); + if (tb[IFLA_TXQLEN]) { + if (dev->tx_queue_len != nla_get_u32(tb[IFLA_TXQLEN])) { + dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); + modified = 1; + } + } if (tb[IFLA_OPERSTATE]) - set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); + modified |= set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]), false); if (tb[IFLA_LINKMODE]) { - write_lock_bh(&dev_base_lock); - dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); - write_unlock_bh(&dev_base_lock); + if (dev->link_mode != nla_get_u8(tb[IFLA_LINKMODE])) { + write_lock_bh(&dev_base_lock); + dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); + write_lock_bh(&dev_base_lock); + modified = 1; + } } err = 0; @@ -857,6 +869,10 @@ errout: if (send_addr_notify) call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); + + if (modified) + netdev_state_change(dev); + return err; } @@ -974,7 +990,7 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname, if (tb[IFLA_TXQLEN]) dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); if (tb[IFLA_OPERSTATE]) - set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); + set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]), true); if (tb[IFLA_LINKMODE]) dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 4e354221ec23..0d0fd28a9041 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1907,11 +1907,11 @@ void skb_prepare_seq_read(struct sk_buff *skb, unsigned int from, * of bytes already consumed and the next call to * skb_seq_read() will return the remaining part of the block. * - * Note: The size of each block of data returned can be arbitary, + * Note 1: The size of each block of data returned can be arbitary, * this limitation is the cost for zerocopy seqeuental * reads of potentially non linear data. * - * Note: Fragment lists within fragments are not implemented + * Note 2: Fragment lists within fragments are not implemented * at the moment, state->root_skb could be replaced with * a stack for this purpose. */ @@ -2106,11 +2106,10 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, /** * skb_pull_rcsum - pull skb and update receive checksum * @skb: buffer to update - * @start: start of data before pull * @len: length of data pulled * * This function performs an skb_pull on the packet and updates - * update the CHECKSUM_COMPLETE checksum. It should be used on + * the CHECKSUM_COMPLETE checksum. It should be used on * receive path processing instead of skb_pull unless you know * that the checksum difference is zero (e.g., a valid IP header) * or you are setting ip_summed to CHECKSUM_NONE. diff --git a/net/core/sock.c b/net/core/sock.c index 433715fb141a..09cb3a74de7f 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1731,7 +1731,7 @@ void sock_init_data(struct socket *sock, struct sock *sk) atomic_set(&sk->sk_drops, 0); } -void fastcall lock_sock_nested(struct sock *sk, int subclass) +void lock_sock_nested(struct sock *sk, int subclass) { might_sleep(); spin_lock_bh(&sk->sk_lock.slock); @@ -1748,7 +1748,7 @@ void fastcall lock_sock_nested(struct sock *sk, int subclass) EXPORT_SYMBOL(lock_sock_nested); -void fastcall release_sock(struct sock *sk) +void release_sock(struct sock *sk) { /* * The sk_lock has mutex_unlock() semantics: diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 31be29b8b5a3..9dc0abb50eaf 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -94,7 +94,7 @@ struct dn_rt_hash_bucket { struct dn_route *chain; spinlock_t lock; -} __attribute__((__aligned__(8))); +}; extern struct neigh_table dn_neigh_table; diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 9d4555ec0b59..8219b7e0968d 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -96,7 +96,7 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) ah->reserved = 0; ah->spi = x->id.spi; - ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq); + ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); spin_lock_bh(&x->lock); err = ah_mac_digest(ahp, skb, ah->auth_data); diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 8e17f65f4002..c663fa5339ee 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -368,7 +368,6 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) if (!(neigh->nud_state&NUD_VALID)) printk(KERN_DEBUG "trying to ucast probe in NUD_INVALID\n"); dst_ha = neigh->ha; - read_lock_bh(&neigh->lock); } else if ((probes -= neigh->parms->app_probes) < 0) { #ifdef CONFIG_ARPD neigh_app_ns(neigh); @@ -378,8 +377,6 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) arp_send(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr, dst_ha, dev->dev_addr, NULL); - if (dst_ha) - read_unlock_bh(&neigh->lock); } static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 258d17631b4b..091e6709f831 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -199,7 +199,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) } esph->spi = x->id.spi; - esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq); + esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); sg_init_table(sg, nfrags); skb_to_sgvec(skb, sg, @@ -210,7 +210,8 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) aead_givcrypt_set_callback(req, 0, esp_output_done, skb); aead_givcrypt_set_crypt(req, sg, sg, clen, iv); aead_givcrypt_set_assoc(req, asg, sizeof(*esph)); - aead_givcrypt_set_giv(req, esph->enc_data, XFRM_SKB_CB(skb)->seq); + aead_givcrypt_set_giv(req, esph->enc_data, + XFRM_SKB_CB(skb)->seq.output); ESP_SKB_CB(skb)->tmp = tmp; err = crypto_aead_givencrypt(req); diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index f5fba3f71c06..1ff446d0fa8b 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1762,11 +1762,9 @@ static struct leaf *trie_leafindex(struct trie *t, int index) { struct leaf *l = trie_firstleaf(t); - while (index-- > 0) { + while (l && index-- > 0) l = trie_nextleaf(l); - if (!l) - break; - } + return l; } @@ -2461,6 +2459,84 @@ static const struct file_operations fib_trie_fops = { .release = seq_release_net, }; +struct fib_route_iter { + struct seq_net_private p; + struct trie *main_trie; + loff_t pos; + t_key key; +}; + +static struct leaf *fib_route_get_idx(struct fib_route_iter *iter, loff_t pos) +{ + struct leaf *l = NULL; + struct trie *t = iter->main_trie; + + /* use cache location of last found key */ + if (iter->pos > 0 && pos >= iter->pos && (l = fib_find_node(t, iter->key))) + pos -= iter->pos; + else { + iter->pos = 0; + l = trie_firstleaf(t); + } + + while (l && pos-- > 0) { + iter->pos++; + l = trie_nextleaf(l); + } + + if (l) + iter->key = pos; /* remember it */ + else + iter->pos = 0; /* forget it */ + + return l; +} + +static void *fib_route_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(RCU) +{ + struct fib_route_iter *iter = seq->private; + struct fib_table *tb; + + rcu_read_lock(); + tb = fib_get_table(iter->p.net, RT_TABLE_MAIN); + if (!tb) + return NULL; + + iter->main_trie = (struct trie *) tb->tb_data; + if (*pos == 0) + return SEQ_START_TOKEN; + else + return fib_route_get_idx(iter, *pos - 1); +} + +static void *fib_route_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct fib_route_iter *iter = seq->private; + struct leaf *l = v; + + ++*pos; + if (v == SEQ_START_TOKEN) { + iter->pos = 0; + l = trie_firstleaf(iter->main_trie); + } else { + iter->pos++; + l = trie_nextleaf(l); + } + + if (l) + iter->key = l->key; + else + iter->pos = 0; + return l; +} + +static void fib_route_seq_stop(struct seq_file *seq, void *v) + __releases(RCU) +{ + rcu_read_unlock(); +} + static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi) { static unsigned type2flags[RTN_MAX + 1] = { @@ -2484,7 +2560,6 @@ static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi) */ static int fib_route_seq_show(struct seq_file *seq, void *v) { - const struct fib_trie_iter *iter = seq->private; struct leaf *l = v; struct leaf_info *li; struct hlist_node *node; @@ -2496,12 +2571,6 @@ static int fib_route_seq_show(struct seq_file *seq, void *v) return 0; } - if (iter->trie == iter->trie_local) - return 0; - - if (IS_TNODE(l)) - return 0; - hlist_for_each_entry_rcu(li, node, &l->list, hlist) { struct fib_alias *fa; __be32 mask, prefix; @@ -2544,16 +2613,16 @@ static int fib_route_seq_show(struct seq_file *seq, void *v) } static const struct seq_operations fib_route_seq_ops = { - .start = fib_trie_seq_start, - .next = fib_trie_seq_next, - .stop = fib_trie_seq_stop, + .start = fib_route_seq_start, + .next = fib_route_seq_next, + .stop = fib_route_seq_stop, .show = fib_route_seq_show, }; static int fib_route_seq_open(struct inode *inode, struct file *file) { return seq_open_net(inode, file, &fib_route_seq_ops, - sizeof(struct fib_trie_iter)); + sizeof(struct fib_route_iter)); } static const struct file_operations fib_route_fops = { diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 994648be80ab..732cd07e6071 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -922,13 +922,11 @@ int igmp_rcv(struct sk_buff *skb) struct in_device *in_dev = in_dev_get(skb->dev); int len = skb->len; - if (in_dev==NULL) { - kfree_skb(skb); - return 0; - } + if (in_dev == NULL) + goto drop; if (!pskb_may_pull(skb, sizeof(struct igmphdr))) - goto drop; + goto drop_ref; switch (skb->ip_summed) { case CHECKSUM_COMPLETE: @@ -938,7 +936,7 @@ int igmp_rcv(struct sk_buff *skb) case CHECKSUM_NONE: skb->csum = 0; if (__skb_checksum_complete(skb)) - goto drop; + goto drop_ref; } ih = igmp_hdr(skb); @@ -972,8 +970,9 @@ int igmp_rcv(struct sk_buff *skb) break; } -drop: +drop_ref: in_dev_put(in_dev); +drop: kfree_skb(skb); return 0; } diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 9cac6c034abd..1aba606f6bbb 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -120,8 +120,6 @@ void inet_listen_wlock(struct inet_hashinfo *hashinfo) } } -EXPORT_SYMBOL(inet_listen_wlock); - /* * Don't inline this cruft. Here are some nice properties to exploit here. The * BSD API does not allow a listening sock to specify the remote port nor the @@ -494,7 +492,6 @@ out: return ret; } } -EXPORT_SYMBOL_GPL(__inet_hash_connect); /* * Bind a port for a connect operation and hash it. diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 754b0a5bbfe9..de0572c88859 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -514,11 +514,6 @@ static int do_ip_setsockopt(struct sock *sk, int level, val &= ~3; val |= inet->tos & 3; } - if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP && - !capable(CAP_NET_ADMIN)) { - err = -EPERM; - break; - } if (inet->tos != val) { inet->tos = val; sk->sk_priority = rt_tos2priority(val); diff --git a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c index 749fa044eca5..85c680add6df 100644 --- a/net/ipv4/ipvs/ip_vs_wrr.c +++ b/net/ipv4/ipvs/ip_vs_wrr.c @@ -22,6 +22,7 @@ #include <linux/module.h> #include <linux/kernel.h> +#include <linux/net.h> #include <net/ip_vs.h> @@ -169,7 +170,7 @@ ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) */ if (mark->cw == 0) { mark->cl = &svc->destinations; - IP_VS_INFO("ip_vs_wrr_schedule(): " + IP_VS_ERR_RL("ip_vs_wrr_schedule(): " "no available servers\n"); dest = NULL; goto out; diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index dd07362d2b8f..0d5fa3a54d04 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -600,10 +600,10 @@ static void nf_nat_cleanup_conntrack(struct nf_conn *ct) spin_unlock_bh(&nf_nat_lock); } -static void nf_nat_move_storage(struct nf_conn *conntrack, void *old) +static void nf_nat_move_storage(void *new, void *old) { - struct nf_conn_nat *new_nat = nf_ct_ext_find(conntrack, NF_CT_EXT_NAT); - struct nf_conn_nat *old_nat = (struct nf_conn_nat *)old; + struct nf_conn_nat *new_nat = new; + struct nf_conn_nat *old_nat = old; struct nf_conn *ct = old_nat->ct; if (!ct || !(ct->status & IPS_NAT_DONE_MASK)) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 8842ecb9be48..525787b52b72 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2041,7 +2041,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, int iif = dev->ifindex; struct net *net; - net = skb->dev->nd_net; + net = dev->nd_net; tos &= IPTOS_RT_MASK; hash = rt_hash(daddr, saddr, iif); diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 379c8e04c36c..2ff0c8233e47 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -283,7 +283,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) ah->reserved = 0; ah->spi = x->id.spi; - ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq); + ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); spin_lock_bh(&x->lock); err = ah_mac_digest(ahp, skb, ah->auth_data); diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 8e0f1428c716..0ec1402320ea 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -188,7 +188,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) *skb_mac_header(skb) = IPPROTO_ESP; esph->spi = x->id.spi; - esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq); + esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); sg_init_table(sg, nfrags); skb_to_sgvec(skb, sg, @@ -199,7 +199,8 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) aead_givcrypt_set_callback(req, 0, esp_output_done, skb); aead_givcrypt_set_crypt(req, sg, sg, clen, iv); aead_givcrypt_set_assoc(req, asg, sizeof(*esph)); - aead_givcrypt_set_giv(req, esph->enc_data, XFRM_SKB_CB(skb)->seq); + aead_givcrypt_set_giv(req, esph->enc_data, + XFRM_SKB_CB(skb)->seq.output); ESP_SKB_CB(skb)->tmp = tmp; err = crypto_aead_givencrypt(req); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 9ac6ca2521c3..8b67ca07467d 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -621,7 +621,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) * or if the skb it not generated by a local socket. (This last * check should be redundant, but it's free.) */ - if (!np || np->pmtudisc >= IPV6_PMTUDISC_DO) { + if (!skb->local_df) { skb->dev = skb->dst->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS); @@ -1420,6 +1420,10 @@ int ip6_push_pending_frames(struct sock *sk) tmp_skb->sk = NULL; } + /* Allow local fragmentation. */ + if (np->pmtudisc < IPV6_PMTUDISC_DO) + skb->local_df = 1; + ipv6_addr_copy(final_dst, &fl->fl6_dst); __skb_pull(skb, skb_network_header_len(skb)); if (opt && opt->opt_flen) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 513f72e3db0d..6e7b56ef4449 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1620,7 +1620,7 @@ static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixle { struct fib6_config cfg = { .fc_table = RT6_TABLE_INFO, - .fc_metric = 1024, + .fc_metric = IP6_RT_PRIO_USER, .fc_ifindex = ifindex, .fc_dst_len = prefixlen, .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | @@ -1670,7 +1670,7 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, { struct fib6_config cfg = { .fc_table = RT6_TABLE_DFLT, - .fc_metric = 1024, + .fc_metric = IP6_RT_PRIO_USER, .fc_ifindex = dev->ifindex, .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES | RTF_PREF(pref), diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index b34c58c65656..79ccfb080733 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -36,7 +36,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb) if (mtu < IPV6_MIN_MTU) mtu = IPV6_MIN_MTU; - if (skb->len > mtu) { + if (!skb->local_df && skb->len > mtu) { skb->dev = dst->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); ret = -EMSGSIZE; diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 2255e3c082ed..fee22caf1bad 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -482,6 +482,10 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, /* Create path. */ iucv->path = iucv_path_alloc(IUCV_QUEUELEN_DEFAULT, IPRMDATA, GFP_KERNEL); + if (!iucv->path) { + err = -ENOMEM; + goto done; + } err = iucv_path_connect(iucv->path, &af_iucv_handler, sa->siucv_user_id, NULL, user_data, sk); if (err) { @@ -1094,6 +1098,8 @@ static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg) save_message: save_msg = kzalloc(sizeof(struct sock_msg_q), GFP_ATOMIC | GFP_DMA); + if (!save_msg) + return; save_msg->path = path; save_msg->msg = *msg; @@ -1106,24 +1112,31 @@ static void iucv_callback_txdone(struct iucv_path *path, struct iucv_message *msg) { struct sock *sk = path->private; - struct sk_buff *this; + struct sk_buff *this = NULL; struct sk_buff_head *list = &iucv_sk(sk)->send_skb_q; struct sk_buff *list_skb = list->next; unsigned long flags; - if (list_skb) { + if (!skb_queue_empty(list)) { spin_lock_irqsave(&list->lock, flags); - do { - this = list_skb; + while (list_skb != (struct sk_buff *)list) { + if (!memcmp(&msg->tag, list_skb->cb, 4)) { + this = list_skb; + break; + } list_skb = list_skb->next; - } while (memcmp(&msg->tag, this->cb, 4) && list_skb); + } + if (this) + __skb_unlink(this, list); spin_unlock_irqrestore(&list->lock, flags); - skb_unlink(this, &iucv_sk(sk)->send_skb_q); - kfree_skb(this); + if (this) + kfree_skb(this); } + if (!this) + printk(KERN_ERR "AF_IUCV msg tag %u not found\n", msg->tag); if (sk->sk_state == IUCV_CLOSING) { if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) { diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index f13fe8821cbd..2753b0c448f3 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -693,9 +693,9 @@ int iucv_register(struct iucv_handler *handler, int smp) iucv_setmask_up(); INIT_LIST_HEAD(&handler->paths); - spin_lock_irq(&iucv_table_lock); + spin_lock_bh(&iucv_table_lock); list_add_tail(&handler->list, &iucv_handler_list); - spin_unlock_irq(&iucv_table_lock); + spin_unlock_bh(&iucv_table_lock); rc = 0; out_mutex: mutex_unlock(&iucv_register_mutex); diff --git a/net/key/af_key.c b/net/key/af_key.c index 45c3c27d279a..1c853927810a 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -2291,6 +2291,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h return 0; out: + xp->dead = 1; xfrm_policy_destroy(xp); return err; } @@ -3734,21 +3735,15 @@ static struct net_proto_family pfkey_family_ops = { }; #ifdef CONFIG_PROC_FS -static int pfkey_read_proc(char *buffer, char **start, off_t offset, - int length, int *eof, void *data) +static int pfkey_seq_show(struct seq_file *f, void *v) { - off_t pos = 0; - off_t begin = 0; - int len = 0; struct sock *s; - struct hlist_node *node; - - len += sprintf(buffer,"sk RefCnt Rmem Wmem User Inode\n"); - - read_lock(&pfkey_table_lock); - sk_for_each(s, node, &pfkey_table) { - len += sprintf(buffer+len,"%p %-6d %-6u %-6u %-6u %-6lu", + s = (struct sock *)v; + if (v == SEQ_START_TOKEN) + seq_printf(f ,"sk RefCnt Rmem Wmem User Inode\n"); + else + seq_printf(f ,"%p %-6d %-6u %-6u %-6u %-6lu\n", s, atomic_read(&s->sk_refcnt), atomic_read(&s->sk_rmem_alloc), @@ -3756,31 +3751,82 @@ static int pfkey_read_proc(char *buffer, char **start, off_t offset, sock_i_uid(s), sock_i_ino(s) ); + return 0; +} - buffer[len++] = '\n'; +static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos) +{ + struct sock *s; + struct hlist_node *node; + loff_t pos = *ppos; - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if(pos > offset + length) - goto done; - } - *eof = 1; + read_lock(&pfkey_table_lock); + if (pos == 0) + return SEQ_START_TOKEN; -done: + sk_for_each(s, node, &pfkey_table) + if (pos-- == 1) + return s; + + return NULL; +} + +static void *pfkey_seq_next(struct seq_file *f, void *v, loff_t *ppos) +{ + ++*ppos; + return (v == SEQ_START_TOKEN) ? + sk_head(&pfkey_table) : + sk_next((struct sock *)v); +} + +static void pfkey_seq_stop(struct seq_file *f, void *v) +{ read_unlock(&pfkey_table_lock); +} + +static struct seq_operations pfkey_seq_ops = { + .start = pfkey_seq_start, + .next = pfkey_seq_next, + .stop = pfkey_seq_stop, + .show = pfkey_seq_show, +}; + +static int pfkey_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &pfkey_seq_ops); +} - *start = buffer + (offset - begin); - len -= (offset - begin); +static struct file_operations pfkey_proc_ops = { + .open = pfkey_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; - if (len > length) - len = length; - if (len < 0) - len = 0; +static int pfkey_init_proc(void) +{ + struct proc_dir_entry *e; - return len; + e = create_proc_entry("pfkey", 0, init_net.proc_net); + if (e == NULL) + return -ENOMEM; + + e->proc_fops = &pfkey_proc_ops; + return 0; +} + +static void pfkey_exit_proc(void) +{ + remove_proc_entry("net/pfkey", NULL); +} +#else +static inline int pfkey_init_proc(void) +{ + return 0; +} + +static inline void pfkey_exit_proc(void) +{ } #endif @@ -3798,7 +3844,7 @@ static struct xfrm_mgr pfkeyv2_mgr = static void __exit ipsec_pfkey_exit(void) { xfrm_unregister_km(&pfkeyv2_mgr); - remove_proc_entry("pfkey", init_net.proc_net); + pfkey_exit_proc(); sock_unregister(PF_KEY); proto_unregister(&key_proto); } @@ -3813,21 +3859,17 @@ static int __init ipsec_pfkey_init(void) err = sock_register(&pfkey_family_ops); if (err != 0) goto out_unregister_key_proto; -#ifdef CONFIG_PROC_FS - err = -ENOMEM; - if (create_proc_read_entry("pfkey", 0, init_net.proc_net, pfkey_read_proc, NULL) == NULL) + err = pfkey_init_proc(); + if (err != 0) goto out_sock_unregister; -#endif err = xfrm_register_km(&pfkeyv2_mgr); if (err != 0) goto out_remove_proc_entry; out: return err; out_remove_proc_entry: -#ifdef CONFIG_PROC_FS - remove_proc_entry("net/pfkey", NULL); + pfkey_exit_proc(); out_sock_unregister: -#endif sock_unregister(PF_KEY); out_unregister_key_proto: proto_unregister(&key_proto); diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index e77592d050ce..45c7c0c3875e 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -1,6 +1,5 @@ config MAC80211 tristate "Generic IEEE 802.11 Networking Stack (mac80211)" - depends on EXPERIMENTAL select CRYPTO select CRYPTO_ECB select CRYPTO_ARC4 diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c index cf6ba6659a80..8b9be1e978cd 100644 --- a/net/netfilter/nf_conntrack_extend.c +++ b/net/netfilter/nf_conntrack_extend.c @@ -109,7 +109,8 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp) rcu_read_lock(); t = rcu_dereference(nf_ct_ext_types[i]); if (t && t->move) - t->move(ct, ct->ext + ct->ext->offset[i]); + t->move((void *)new + new->offset[i], + (void *)ct->ext + ct->ext->offset[i]); rcu_read_unlock(); } kfree(ct->ext); diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 3e0cccae5636..62567959b66e 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -125,7 +125,7 @@ enum tcp_bit_set { * CLOSE_WAIT: ACK seen (after FIN) * LAST_ACK: FIN seen (after FIN) * TIME_WAIT: last ACK seen - * CLOSE: closed connection + * CLOSE: closed connection (RST) * * LISTEN state is not used. * @@ -824,7 +824,21 @@ static int tcp_packet(struct nf_conn *ct, case TCP_CONNTRACK_SYN_SENT: if (old_state < TCP_CONNTRACK_TIME_WAIT) break; - if ((ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_CLOSE_INIT) + /* RFC 1122: "When a connection is closed actively, + * it MUST linger in TIME-WAIT state for a time 2xMSL + * (Maximum Segment Lifetime). However, it MAY accept + * a new SYN from the remote TCP to reopen the connection + * directly from TIME-WAIT state, if..." + * We ignore the conditions because we are in the + * TIME-WAIT state anyway. + * + * Handle aborted connections: we and the server + * think there is an existing connection but the client + * aborts it and starts a new one. + */ + if (((ct->proto.tcp.seen[dir].flags + | ct->proto.tcp.seen[!dir].flags) + & IP_CT_TCP_FLAG_CLOSE_INIT) || (ct->proto.tcp.last_dir == dir && ct->proto.tcp.last_index == TCP_RST_SET)) { /* Attempt to reopen a closed/aborted connection. @@ -838,15 +852,22 @@ static int tcp_packet(struct nf_conn *ct, case TCP_CONNTRACK_IGNORE: /* Ignored packets: * + * Our connection entry may be out of sync, so ignore + * packets which may signal the real connection between + * the client and the server. + * * a) SYN in ORIGINAL * b) SYN/ACK in REPLY * c) ACK in reply direction after initial SYN in original. + * + * If the ignored packet is invalid, the receiver will send + * a RST we'll catch below. */ if (index == TCP_SYNACK_SET && ct->proto.tcp.last_index == TCP_SYN_SET && ct->proto.tcp.last_dir != dir && ntohl(th->ack_seq) == ct->proto.tcp.last_end) { - /* This SYN/ACK acknowledges a SYN that we earlier + /* b) This SYN/ACK acknowledges a SYN that we earlier * ignored as invalid. This means that the client and * the server are both in sync, while the firewall is * not. We kill this session and block the SYN/ACK so @@ -870,7 +891,7 @@ static int tcp_packet(struct nf_conn *ct, write_unlock_bh(&tcp_lock); if (LOG_INVALID(IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, - "nf_ct_tcp: invalid packed ignored "); + "nf_ct_tcp: invalid packet ignored "); return NF_ACCEPT; case TCP_CONNTRACK_MAX: /* Invalid packet */ @@ -924,8 +945,7 @@ static int tcp_packet(struct nf_conn *ct, ct->proto.tcp.state = new_state; if (old_state != new_state - && (new_state == TCP_CONNTRACK_FIN_WAIT - || new_state == TCP_CONNTRACK_CLOSE)) + && new_state == TCP_CONNTRACK_FIN_WAIT) ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT; timeout = ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans && tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c index 7708e2084ce2..c0284856ccd4 100644 --- a/net/netfilter/xt_SECMARK.c +++ b/net/netfilter/xt_SECMARK.c @@ -111,7 +111,7 @@ secmark_tg_check(const char *tablename, const void *entry, return true; } -void secmark_tg_destroy(const struct xt_target *target, void *targinfo) +static void secmark_tg_destroy(const struct xt_target *target, void *targinfo) { switch (mode) { case SECMARK_MODE_SEL: diff --git a/net/netfilter/xt_iprange.c b/net/netfilter/xt_iprange.c index 01035fc0e140..4f984dc60319 100644 --- a/net/netfilter/xt_iprange.c +++ b/net/netfilter/xt_iprange.c @@ -13,6 +13,7 @@ #include <linux/ip.h> #include <linux/ipv6.h> #include <linux/netfilter/x_tables.h> +#include <linux/netfilter/xt_iprange.h> #include <linux/netfilter_ipv4/ipt_iprange.h> static bool @@ -148,7 +149,7 @@ static struct xt_match iprange_mt_reg[] __read_mostly = { { .name = "iprange", .revision = 1, - .family = AF_INET6, + .family = AF_INET, .match = iprange_mt4, .matchsize = sizeof(struct xt_iprange_mtinfo), .me = THIS_MODULE, diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index 9a8ea0195c4f..fd462313471c 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c @@ -150,11 +150,11 @@ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain) entry = netlbl_domhsh_search(domain); if (entry == NULL) { entry = rcu_dereference(netlbl_domhsh_def); - if (entry != NULL && entry->valid) - return entry; + if (entry != NULL && !entry->valid) + entry = NULL; } - return NULL; + return entry; } /* diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 42e81fd8cc49..3e745b72fded 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -180,6 +180,7 @@ static void netlbl_unlabel_audit_addr4(struct audit_buffer *audit_buf, } } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) /** * netlbl_unlabel_audit_addr6 - Audit an IPv6 address * @audit_buf: audit buffer @@ -213,6 +214,7 @@ static void netlbl_unlabel_audit_addr6(struct audit_buffer *audit_buf, audit_log_format(audit_buf, " src_prefixlen=%d", mask_len); } } +#endif /* IPv6 */ /* * Unlabeled Connection Hash Table Functions @@ -617,8 +619,6 @@ static int netlbl_unlhsh_add(struct net *net, int ifindex; struct net_device *dev; struct netlbl_unlhsh_iface *iface; - struct in_addr *addr4, *mask4; - struct in6_addr *addr6, *mask6; struct audit_buffer *audit_buf = NULL; char *secctx = NULL; u32 secctx_len; @@ -651,7 +651,9 @@ static int netlbl_unlhsh_add(struct net *net, audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCADD, audit_info); switch (addr_len) { - case sizeof(struct in_addr): + case sizeof(struct in_addr): { + struct in_addr *addr4, *mask4; + addr4 = (struct in_addr *)addr; mask4 = (struct in_addr *)mask; ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid); @@ -661,8 +663,11 @@ static int netlbl_unlhsh_add(struct net *net, addr4->s_addr, mask4->s_addr); break; + } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - case sizeof(struct in6_addr): + case sizeof(struct in6_addr): { + struct in6_addr *addr6, *mask6; + addr6 = (struct in6_addr *)addr; mask6 = (struct in6_addr *)mask; ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid); @@ -671,6 +676,7 @@ static int netlbl_unlhsh_add(struct net *net, dev_name, addr6, mask6); break; + } #endif /* IPv6 */ default: ret_val = -EINVAL; @@ -1741,10 +1747,6 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb, u16 family, struct netlbl_lsm_secattr *secattr) { - struct iphdr *hdr4; - struct ipv6hdr *hdr6; - struct netlbl_unlhsh_addr4 *addr4; - struct netlbl_unlhsh_addr6 *addr6; struct netlbl_unlhsh_iface *iface; rcu_read_lock(); @@ -1752,21 +1754,29 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb, if (iface == NULL) goto unlabel_getattr_nolabel; switch (family) { - case PF_INET: + case PF_INET: { + struct iphdr *hdr4; + struct netlbl_unlhsh_addr4 *addr4; + hdr4 = ip_hdr(skb); addr4 = netlbl_unlhsh_search_addr4(hdr4->saddr, iface); if (addr4 == NULL) goto unlabel_getattr_nolabel; secattr->attr.secid = addr4->secid; break; + } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - case PF_INET6: + case PF_INET6: { + struct ipv6hdr *hdr6; + struct netlbl_unlhsh_addr6 *addr6; + hdr6 = ipv6_hdr(skb); addr6 = netlbl_unlhsh_search_addr6(&hdr6->saddr, iface); if (addr6 == NULL) goto unlabel_getattr_nolabel; secattr->attr.secid = addr6->secid; break; + } #endif /* IPv6 */ default: goto unlabel_getattr_nolabel; diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c index 85a96a3fddaa..023fc8fe840d 100644 --- a/net/netlabel/netlabel_user.c +++ b/net/netlabel/netlabel_user.c @@ -96,7 +96,6 @@ int netlbl_netlink_init(void) struct audit_buffer *netlbl_audit_start_common(int type, struct netlbl_audit *audit_info) { - struct audit_context *audit_ctx = current->audit_context; struct audit_buffer *audit_buf; char *secctx; u32 secctx_len; @@ -104,7 +103,7 @@ struct audit_buffer *netlbl_audit_start_common(int type, if (audit_enabled == 0) return NULL; - audit_buf = audit_log_start(audit_ctx, GFP_ATOMIC, type); + audit_buf = audit_log_start(current->audit_context, GFP_ATOMIC, type); if (audit_buf == NULL) return NULL; diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 150579a21469..d16929c9b4bc 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -230,10 +230,8 @@ static void genl_unregister_mc_groups(struct genl_family *family) { struct genl_multicast_group *grp, *tmp; - genl_lock(); list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list) __genl_unregister_mc_group(family, grp); - genl_unlock(); } /** @@ -396,10 +394,10 @@ int genl_unregister_family(struct genl_family *family) { struct genl_family *rc; - genl_unregister_mc_groups(family); - genl_lock(); + genl_unregister_mc_groups(family); + list_for_each_entry(rc, genl_family_chain(family->id), family_list) { if (family->id != rc->id || strcmp(rc->name, family->name)) continue; diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 5e82f1c0afbb..2d0c29c837f7 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -239,7 +239,7 @@ static struct rxrpc_transport *rxrpc_name_to_transport(struct socket *sock, /* find a remote transport endpoint from the local one */ peer = rxrpc_get_peer(srx, gfp); if (IS_ERR(peer)) - return ERR_PTR(PTR_ERR(peer)); + return ERR_CAST(peer); /* find a transport */ trans = rxrpc_get_transport(rx->local, peer, gfp); @@ -282,7 +282,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, trans = rxrpc_name_to_transport(sock, (struct sockaddr *) srx, sizeof(*srx), 0, gfp); if (IS_ERR(trans)) { - call = ERR_PTR(PTR_ERR(trans)); + call = ERR_CAST(trans); trans = NULL; goto out; } @@ -306,7 +306,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, bundle = rxrpc_get_bundle(rx, trans, key, service_id, gfp); if (IS_ERR(bundle)) { - call = ERR_PTR(PTR_ERR(bundle)); + call = ERR_CAST(bundle); goto out; } diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 8d7698621f0a..971b867e0484 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -19,6 +19,7 @@ #include <linux/in.h> #include <linux/ip.h> #include <linux/ipv6.h> +#include <linux/if_vlan.h> #include <net/pkt_cls.h> #include <net/ip.h> @@ -270,6 +271,15 @@ static u32 flow_get_skgid(const struct sk_buff *skb) return 0; } +static u32 flow_get_vlan_tag(const struct sk_buff *skb) +{ + u16 uninitialized_var(tag); + + if (vlan_get_tag(skb, &tag) < 0) + return 0; + return tag & VLAN_VID_MASK; +} + static u32 flow_key_get(const struct sk_buff *skb, int key) { switch (key) { @@ -305,6 +315,8 @@ static u32 flow_key_get(const struct sk_buff *skb, int key) return flow_get_skuid(skb); case FLOW_KEY_SKGID: return flow_get_skgid(skb); + case FLOW_KEY_VLAN_TAG: + return flow_get_vlan_tag(skb); default: WARN_ON(1); return 0; @@ -402,12 +414,13 @@ static int flow_change(struct tcf_proto *tp, unsigned long base, if (tb[TCA_FLOW_KEYS]) { keymask = nla_get_u32(tb[TCA_FLOW_KEYS]); - if (fls(keymask) - 1 > FLOW_KEY_MAX) - return -EOPNOTSUPP; nkeys = hweight32(keymask); if (nkeys == 0) return -EINVAL; + + if (fls(keymask) - 1 > FLOW_KEY_MAX) + return -EOPNOTSUPP; } err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &flow_ext_map); diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index 9c2ec1992a2a..3da4129b89d1 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -176,7 +176,7 @@ META_COLLECTOR(var_dev) META_COLLECTOR(int_vlan_tag) { - unsigned short tag; + unsigned short uninitialized_var(tag); if (vlan_get_tag(skb, &tag) < 0) *err = -1; else @@ -687,8 +687,8 @@ static inline struct meta_type_ops * meta_type_ops(struct meta_value *v) * Core **************************************************************************/ -static inline int meta_get(struct sk_buff *skb, struct tcf_pkt_info *info, - struct meta_value *v, struct meta_obj *dst) +static int meta_get(struct sk_buff *skb, struct tcf_pkt_info *info, + struct meta_value *v, struct meta_obj *dst) { int err = 0; @@ -733,13 +733,15 @@ static int em_meta_match(struct sk_buff *skb, struct tcf_ematch *m, return 0; } -static inline void meta_delete(struct meta_match *meta) +static void meta_delete(struct meta_match *meta) { - struct meta_type_ops *ops = meta_type_ops(&meta->lvalue); + if (meta) { + struct meta_type_ops *ops = meta_type_ops(&meta->lvalue); - if (ops && ops->destroy) { - ops->destroy(&meta->lvalue); - ops->destroy(&meta->rvalue); + if (ops && ops->destroy) { + ops->destroy(&meta->lvalue); + ops->destroy(&meta->rvalue); + } } kfree(meta); diff --git a/net/sched/ematch.c b/net/sched/ematch.c index 74ff918455a2..5e6f82e0e6f3 100644 --- a/net/sched/ematch.c +++ b/net/sched/ematch.c @@ -312,10 +312,9 @@ int tcf_em_tree_validate(struct tcf_proto *tp, struct nlattr *nla, struct tcf_ematch_tree_hdr *tree_hdr; struct tcf_ematch *em; - if (!nla) { - memset(tree, 0, sizeof(*tree)); + memset(tree, 0, sizeof(*tree)); + if (!nla) return 0; - } err = nla_parse_nested(tb, TCA_EMATCH_TREE_MAX, nla, em_policy); if (err < 0) @@ -410,7 +409,7 @@ void tcf_em_tree_destroy(struct tcf_proto *tp, struct tcf_ematch_tree *tree) if (em->ops) { if (em->ops->destroy) em->ops->destroy(tp, em); - else if (!tcf_em_is_simple(em) && em->data) + else if (!tcf_em_is_simple(em)) kfree((void *) em->data); module_put(em->ops->owner); } @@ -418,6 +417,7 @@ void tcf_em_tree_destroy(struct tcf_proto *tp, struct tcf_ematch_tree *tree) tree->hdr.nmatches = 0; kfree(tree->matches); + tree->matches = NULL; } EXPORT_SYMBOL(tcf_em_tree_destroy); diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index e1a579efc215..795c761ad99f 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -609,14 +609,14 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch) /* TODO: requeuing packet charges it to policers again !! */ static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch) { + int ret; struct htb_sched *q = qdisc_priv(sch); - int ret = NET_XMIT_SUCCESS; struct htb_class *cl = htb_classify(skb, sch, &ret); struct sk_buff *tskb; - if (cl == HTB_DIRECT || !cl) { + if (cl == HTB_DIRECT) { /* enqueue to helper queue */ - if (q->direct_queue.qlen < q->direct_qlen && cl) { + if (q->direct_queue.qlen < q->direct_qlen) { __skb_queue_head(&q->direct_queue, skb); } else { __skb_queue_head(&q->direct_queue, skb); @@ -625,6 +625,13 @@ static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch) sch->qstats.drops++; return NET_XMIT_CN; } +#ifdef CONFIG_NET_CLS_ACT + } else if (!cl) { + if (ret == NET_XMIT_BYPASS) + sch->qstats.drops++; + kfree_skb(skb); + return ret; +#endif } else if (cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) { sch->qstats.drops++; diff --git a/net/sctp/associola.c b/net/sctp/associola.c index a016e78061f4..d29f792e0529 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1,21 +1,21 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 La Monte H.P. Yarroll * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * This module provides the abstraction for an SCTP association. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. @@ -1525,7 +1525,7 @@ struct sctp_chunk *sctp_assoc_lookup_asconf_ack( const struct sctp_association *asoc, __be32 serial) { - struct sctp_chunk *ack = NULL; + struct sctp_chunk *ack; /* Walk through the list of cached ASCONF-ACKs and find the * ack chunk whose serial number matches that of the request. @@ -1533,9 +1533,9 @@ struct sctp_chunk *sctp_assoc_lookup_asconf_ack( list_for_each_entry(ack, &asoc->asconf_ack_list, transmitted_list) { if (ack->subh.addip_hdr->serial == serial) { sctp_chunk_hold(ack); - break; + return ack; } } - return ack; + return NULL; } diff --git a/net/sctp/auth.c b/net/sctp/auth.c index ae367c82e512..8bb79f281774 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c @@ -1,15 +1,15 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright 2007 Hewlett-Packard Development Company, L.P. * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index 13fbfb449a55..a27511ebc4cb 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -1,20 +1,20 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2003 * Copyright (c) Cisco 1999,2000 * Copyright (c) Motorola 1999,2000,2001 * Copyright (c) La Monte H.P. Yarroll 2001 * - * This file is part of the SCTP kernel reference implementation. + * This file is part of the SCTP kernel implementation. * * A collection class to handle the storage of transport addresses. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 619d0f2dee51..4d3128f5ccc3 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -1,17 +1,17 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2003, 2004 * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * This file contains the code relating the chunk abstraction. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/command.c b/net/sctp/command.c index 3ff804757f4a..bb977330002a 100644 --- a/net/sctp/command.c +++ b/net/sctp/command.c @@ -1,18 +1,18 @@ -/* SCTP kernel reference Implementation Copyright (C) 1999-2001 +/* SCTP kernel implementation Copyright (C) 1999-2001 * Cisco, Motorola, and IBM * Copyright 2001 La Monte H.P. Yarroll * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * These functions manipulate sctp command sequences. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/debug.c b/net/sctp/debug.c index 80f70aa53386..67715f4eb849 100644 --- a/net/sctp/debug.c +++ b/net/sctp/debug.c @@ -1,25 +1,21 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. * - * This file is part of the SCTP kernel reference Implementation - * - * This file is part of the implementation of the add-IP extension, - * based on <draft-ietf-tsvwg-addip-sctp-02.txt> June 29, 2001, - * for the SCTP kernel reference Implementation. + * This file is part of the SCTP kernel implementation * * This file converts numerical ID value to alphabetical names for SCTP * terms such as chunk type, parameter time, event type, etc. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index de6f505d6ff8..e39a0cdef184 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -1,4 +1,4 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001-2002 International Business Machines, Corp. @@ -6,21 +6,17 @@ * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * This abstraction represents an SCTP endpoint. * - * This file is part of the implementation of the add-IP extension, - * based on <draft-ietf-tsvwg-addip-sctp-02.txt> June 29, 2001, - * for the SCTP kernel reference Implementation. - * - * The SCTP reference implementation is free software; + * The SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * The SCTP implementation 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. diff --git a/net/sctp/input.c b/net/sctp/input.c index d695f710fc77..57fe2f81eca8 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -1,4 +1,4 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001-2003 International Business Machines, Corp. @@ -6,17 +6,17 @@ * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * These functions handle all input from the IP layer into SCTP. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index cf4b7eb023b3..bbf5dd2a97c4 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -1,9 +1,9 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2002 International Business Machines, Corp. * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * These functions are the methods for accessing the SCTP inqueue. * @@ -11,13 +11,13 @@ * (which might be bundles or fragments of chunks) and out of which you * pop SCTP whole chunks. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 74f106a7a7e9..4d7ec961ae1d 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -1,20 +1,20 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2002, 2004 * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2002-2003 Intel Corp. * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * SCTP over IPv6. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/objcnt.c b/net/sctp/objcnt.c index 2cf6ad6ff8ce..14e294e37626 100644 --- a/net/sctp/objcnt.c +++ b/net/sctp/objcnt.c @@ -1,19 +1,19 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * Support for memory object debugging. This allows one to monitor the * object allocations/deallocations for types instrumented for this * via the proc fs. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. @@ -80,61 +80,64 @@ static sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = { /* Callback from procfs to read out objcount information. * Walk through the entries in the sctp_dbg_objcnt array, dumping * the raw object counts for each monitored type. - * - * This code was modified from similar code in route.c */ -static int sctp_dbg_objcnt_read(char *buffer, char **start, off_t offset, - int length, int *eof, void *data) +static int sctp_objcnt_seq_show(struct seq_file *seq, void *v) { - int len = 0; - off_t pos = 0; - int entries; int i; char temp[128]; - /* How many entries? */ - entries = ARRAY_SIZE(sctp_dbg_objcnt); - - /* Walk the entries and print out the debug information - * for proc fs. - */ - for (i = 0; i < entries; i++) { - pos += 128; - - /* Skip ahead. */ - if (pos <= offset) { - len = 0; - continue; - } - /* Print out each entry. */ - sprintf(temp, "%s: %d", - sctp_dbg_objcnt[i].label, - atomic_read(sctp_dbg_objcnt[i].counter)); - - sprintf(buffer + len, "%-127s\n", temp); - len += 128; - if (pos >= offset+length) - goto done; - } - -done: - *start = buffer + len - (pos - offset); - len = pos - offset; - if (len > length) - len = length; - - return len; + i = (int)*(loff_t *)v; + sprintf(temp, "%s: %d", sctp_dbg_objcnt[i].label, + atomic_read(sctp_dbg_objcnt[i].counter)); + seq_printf(seq, "%-127s\n", temp); + return 0; +} + +static void *sctp_objcnt_seq_start(struct seq_file *seq, loff_t *pos) +{ + return (*pos >= ARRAY_SIZE(sctp_dbg_objcnt)) ? NULL : (void *)pos; +} + +static void sctp_objcnt_seq_stop(struct seq_file *seq, void *v) +{ +} + +static void * sctp_objcnt_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + return (*pos >= ARRAY_SIZE(sctp_dbg_objcnt)) ? NULL : (void *)pos; } +static const struct seq_operations sctp_objcnt_seq_ops = { + .start = sctp_objcnt_seq_start, + .next = sctp_objcnt_seq_next, + .stop = sctp_objcnt_seq_stop, + .show = sctp_objcnt_seq_show, +}; + +static int sctp_objcnt_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &sctp_objcnt_seq_ops); +} + +static const struct file_operations sctp_objcnt_ops = { + .open = sctp_objcnt_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + /* Initialize the objcount in the proc filesystem. */ void sctp_dbg_objcnt_init(void) { struct proc_dir_entry *ent; - ent = create_proc_read_entry("sctp_dbg_objcnt", 0, proc_net_sctp, - sctp_dbg_objcnt_read, NULL); + + ent = create_proc_entry("sctp_dbg_objcnt", 0, proc_net_sctp); if (!ent) printk(KERN_WARNING "sctp_dbg_objcnt: Unable to create /proc entry.\n"); + else + ent->proc_fops = &sctp_objcnt_ops; } /* Cleanup the objcount entry in the proc filesystem. */ diff --git a/net/sctp/output.c b/net/sctp/output.c index 5e811b91f21c..aa700feea76c 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -1,19 +1,19 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * These functions handle output processing. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index a42af865c2ef..1bb3c5c35d2a 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -1,21 +1,21 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001-2003 Intel Corp. * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * These functions implement the sctp_outq class. The outqueue handles * bundling and queueing of outgoing SCTP chunks. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. @@ -1179,8 +1179,10 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) tchunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); tsn = ntohl(tchunk->subh.data_hdr->tsn); - if (TSN_lte(tsn, ctsn)) + if (TSN_lte(tsn, ctsn)) { + list_del_init(&tchunk->transmitted_list); sctp_chunk_free(tchunk); + } } /* ii) Set rwnd equal to the newly received a_rwnd minus the diff --git a/net/sctp/primitive.c b/net/sctp/primitive.c index 1b2976d34ac7..8cb4f060bce6 100644 --- a/net/sctp/primitive.c +++ b/net/sctp/primitive.c @@ -1,8 +1,8 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * These functions implement the SCTP primitive functions from Section 10. * @@ -10,13 +10,13 @@ * functions--this file is the functions which populate the struct proto * for SCTP which is the BOTTOM of the sockets interface. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 249973204070..69bb5a63fd8b 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -1,15 +1,15 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * Copyright (c) 2003 International Business Machines, Corp. * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. @@ -38,6 +38,7 @@ #include <linux/seq_file.h> #include <linux/init.h> #include <net/sctp/sctp.h> +#include <net/ip.h> /* for snmp_fold_field */ static struct snmp_mib sctp_snmp_list[] = { SNMP_MIB_ITEM("SctpCurrEstab", SCTP_MIB_CURRESTAB), @@ -75,26 +76,6 @@ static struct snmp_mib sctp_snmp_list[] = { SNMP_MIB_SENTINEL }; -/* Return the current value of a particular entry in the mib by adding its - * per cpu counters. - */ -static unsigned long -fold_field(void *mib[], int nr) -{ - unsigned long res = 0; - int i; - - for_each_possible_cpu(i) { - res += - *((unsigned long *) (((void *) per_cpu_ptr(mib[0], i)) + - sizeof (unsigned long) * nr)); - res += - *((unsigned long *) (((void *) per_cpu_ptr(mib[1], i)) + - sizeof (unsigned long) * nr)); - } - return res; -} - /* Display sctp snmp mib statistics(/proc/net/sctp/snmp). */ static int sctp_snmp_seq_show(struct seq_file *seq, void *v) { @@ -102,7 +83,7 @@ static int sctp_snmp_seq_show(struct seq_file *seq, void *v) for (i = 0; sctp_snmp_list[i].name != NULL; i++) seq_printf(seq, "%-32s\t%ld\n", sctp_snmp_list[i].name, - fold_field((void **)sctp_statistics, + snmp_fold_field((void **)sctp_statistics, sctp_snmp_list[i].entry)); return 0; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 1339742e49f1..22a16571499c 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1,4 +1,4 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. @@ -6,17 +6,17 @@ * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * Initialization/cleanup for SCTP protocol support. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 77383e9b3988..e45be4e3f80d 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1,22 +1,22 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001-2002 Intel Corp. * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * These functions work with the state functions in sctp_sm_statefuns.c * to implement the state operations. These functions implement the * steps which require modifying existing data structures. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. @@ -3224,6 +3224,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc, } /* Free the cached last sent asconf chunk. */ + list_del_init(&asconf->transmitted_list); sctp_chunk_free(asconf); asoc->addip_last_asconf = NULL; diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 78d1a8a49bd0..28eb38eb6083 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1,21 +1,21 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * These functions work with the state functions in sctp_sm_statefuns.c * to implement that state operations. These functions implement the * steps which require modifying existing data structures. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index f98658782d4f..f2ed6473feef 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -1,23 +1,21 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001-2002 Intel Corp. * Copyright (c) 2002 Nokia Corp. * - * This file is part of the SCTP kernel reference Implementation - * - * This is part of the SCTP Linux Kernel Reference Implementation. + * This is part of the SCTP Linux Kernel Implementation. * * These are the state functions for the state machine. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index e6016e41ffa0..d991237fb400 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -1,21 +1,21 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Nokia, Inc. * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * These are the state tables for the SCTP state machine. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 710df67a6785..d47d5787e2e5 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1,4 +1,4 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. @@ -6,7 +6,7 @@ * Copyright (c) 2001-2002 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * These functions interface with the sockets layer to implement the * SCTP Extensions for the Sockets API. @@ -15,13 +15,13 @@ * functions--this file is the functions which populate the struct proto * for SCTP which is the BOTTOM of the sockets interface. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. @@ -1911,7 +1911,8 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, * rwnd by that amount. If all the data in the skb is read, * rwnd is updated when the event is freed. */ - sctp_assoc_rwnd_increase(event->asoc, copied); + if (!sctp_ulpevent_is_notification(event)) + sctp_assoc_rwnd_increase(event->asoc, copied); goto out; } else if ((event->msg_flags & MSG_NOTIFICATION) || (event->msg_flags & MSG_EOR)) @@ -4314,6 +4315,9 @@ static int sctp_copy_laddrs_old(struct sock *sk, __u16 port, (AF_INET6 == addr->a.sa.sa_family)) continue; memcpy(&temp, &addr->a, sizeof(temp)); + if (!temp.v4.sin_port) + temp.v4.sin_port = htons(port); + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), &temp); addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; @@ -4346,6 +4350,9 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, (AF_INET6 == addr->a.sa.sa_family)) continue; memcpy(&temp, &addr->a, sizeof(temp)); + if (!temp.v4.sin_port) + temp.v4.sin_port = htons(port); + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), &temp); addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; diff --git a/net/sctp/ssnmap.c b/net/sctp/ssnmap.c index cbe2513d2822..737d330e5ffc 100644 --- a/net/sctp/ssnmap.c +++ b/net/sctp/ssnmap.c @@ -1,17 +1,17 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * Copyright (c) 2003 International Business Machines, Corp. * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * These functions manipulate sctp SSN tracker. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 5eb6ea829b54..52910697e104 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -1,18 +1,18 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2002, 2004 * Copyright (c) 2002 Intel Corp. * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * Sysctl related interfaces for SCTP. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/transport.c b/net/sctp/transport.c index dfa109341aeb..d9f8af852b56 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -1,23 +1,23 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001-2003 International Business Machines Corp. * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 La Monte H.P. Yarroll * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * This module provides the abstraction for an SCTP tranport representing * a remote transport address. For local transport addresses, we just use * union sctp_addr. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c index 1ff0daade304..f3e58b275905 100644 --- a/net/sctp/tsnmap.c +++ b/net/sctp/tsnmap.c @@ -1,20 +1,20 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * These functions manipulate sctp tsn mapping array. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 047c27df98f4..e27b11f18b7f 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -1,4 +1,4 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. @@ -8,13 +8,14 @@ * * These functions manipulate an sctp event. The struct ulpevent is used * to carry notifications and data to the ULP (sockets). - * The SCTP reference implementation is free software; + * + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index c25caefa3bcb..5061a26c5028 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -1,4 +1,4 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. @@ -8,13 +8,13 @@ * * This abstraction carries sctp events to the ULP (sockets). * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation 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. @@ -283,7 +283,7 @@ out_free: /* 2nd Level Abstractions */ /* Helper function to store chunks that need to be reassembled. */ -static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq, +static void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event) { struct sk_buff *pos; @@ -405,7 +405,7 @@ static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *qu /* Helper function to check if an incoming chunk has filled up the last * missing fragment in a SCTP datagram and return the corresponding event. */ -static inline struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *ulpq) +static struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *ulpq) { struct sk_buff *pos; struct sctp_ulpevent *cevent; @@ -512,7 +512,7 @@ found: } /* Retrieve the next set of fragments of a partial message. */ -static inline struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq *ulpq) +static struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq *ulpq) { struct sk_buff *pos, *last_frag, *first_frag; struct sctp_ulpevent *cevent; @@ -606,7 +606,7 @@ static struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq, } /* Retrieve the first part (sequential fragments) for partial delivery. */ -static inline struct sctp_ulpevent *sctp_ulpq_retrieve_first(struct sctp_ulpq *ulpq) +static struct sctp_ulpevent *sctp_ulpq_retrieve_first(struct sctp_ulpq *ulpq) { struct sk_buff *pos, *last_frag, *first_frag; struct sctp_ulpevent *cevent; @@ -735,7 +735,7 @@ static void sctp_ulpq_reasm_drain(struct sctp_ulpq *ulpq) /* Helper function to gather skbs that have possibly become * ordered by an an incoming chunk. */ -static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq, +static void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event) { struct sk_buff_head *event_list; @@ -779,7 +779,7 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq, } /* Helper function to store chunks needing ordering. */ -static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq, +static void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event) { struct sk_buff *pos; @@ -867,13 +867,14 @@ static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq, /* Helper function to gather skbs that have possibly become * ordered by forward tsn skipping their dependencies. */ -static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid) +static void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid) { struct sk_buff *pos, *tmp; struct sctp_ulpevent *cevent; struct sctp_ulpevent *event; struct sctp_stream *in; struct sk_buff_head temp; + struct sk_buff_head *lobby = &ulpq->lobby; __u16 csid, cssn; in = &ulpq->asoc->ssnmap->in; @@ -881,7 +882,7 @@ static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid) /* We are holding the chunks by stream, by SSN. */ skb_queue_head_init(&temp); event = NULL; - sctp_skb_for_each(pos, &ulpq->lobby, tmp) { + sctp_skb_for_each(pos, lobby, tmp) { cevent = (struct sctp_ulpevent *) pos->cb; csid = cevent->stream; cssn = cevent->ssn; @@ -895,10 +896,10 @@ static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid) continue; /* see if this ssn has been marked by skipping */ - if (!SSN_lte(cssn, sctp_ssn_peek(in, csid))) + if (!SSN_lt(cssn, sctp_ssn_peek(in, csid))) break; - __skb_unlink(pos, &ulpq->lobby); + __skb_unlink(pos, lobby); if (!event) /* Create a temporary list to collect chunks on. */ event = sctp_skb2event(pos); @@ -907,6 +908,22 @@ static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid) __skb_queue_tail(&temp, pos); } + /* If we didn't reap any data, see if the next expected SSN + * is next on the queue and if so, use that. + */ + if (event == NULL && pos != (struct sk_buff *)lobby) { + cevent = (struct sctp_ulpevent *) pos->cb; + csid = cevent->stream; + cssn = cevent->ssn; + + if (csid == sid && cssn == sctp_ssn_peek(in, csid)) { + sctp_ssn_next(in, csid); + __skb_unlink(pos, lobby); + __skb_queue_tail(&temp, pos); + event = sctp_skb2event(pos); + } + } + /* Send event to the ULP. 'event' is the sctp_ulpevent for * very first SKB on the 'temp' list. */ diff --git a/net/socket.c b/net/socket.c index 7651de008502..b6d35cd72a50 100644 --- a/net/socket.c +++ b/net/socket.c @@ -701,6 +701,9 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos, { struct socket *sock = file->private_data; + if (unlikely(!sock->ops->splice_read)) + return -EINVAL; + return sock->ops->splice_read(sock, ppos, pipe, len, flags); } diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 0998e6d09664..8c6a7f1a25e9 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -464,9 +464,9 @@ rpc_release_client(struct rpc_clnt *clnt) /** * rpc_bind_new_program - bind a new RPC program to an existing client - * @old - old rpc_client - * @program - rpc program to set - * @vers - rpc program version + * @old: old rpc_client + * @program: rpc program to set + * @vers: rpc program version * * Clones the rpc client and sets up a new RPC program. This is mainly * of use for enabling different RPC programs to share the same transport. @@ -575,7 +575,7 @@ EXPORT_SYMBOL_GPL(rpc_call_sync); * @clnt: pointer to RPC client * @msg: RPC call parameters * @flags: RPC call flags - * @ops: RPC call ops + * @tk_ops: RPC call ops * @data: user call data */ int @@ -610,7 +610,7 @@ EXPORT_SYMBOL_GPL(rpc_call_start); * rpc_peeraddr - extract remote peer address from clnt's xprt * @clnt: RPC client structure * @buf: target buffer - * @size: length of target buffer + * @bufsize: length of target buffer * * Returns the number of bytes that are actually in the stored address. */ diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 7e197168a245..1b395a41a8b2 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -495,7 +495,7 @@ rpc_lookup_parent(char *path, struct nameidata *nd) static void rpc_release_path(struct nameidata *nd) { - path_release(nd); + path_put(&nd->path); rpc_put_mount(); } @@ -668,7 +668,8 @@ rpc_lookup_negative(char *path, struct nameidata *nd) if ((error = rpc_lookup_parent(path, nd)) != 0) return ERR_PTR(error); - dentry = rpc_lookup_create(nd->dentry, nd->last.name, nd->last.len, 1); + dentry = rpc_lookup_create(nd->path.dentry, nd->last.name, nd->last.len, + 1); if (IS_ERR(dentry)) rpc_release_path(nd); return dentry; @@ -677,7 +678,7 @@ rpc_lookup_negative(char *path, struct nameidata *nd) /** * rpc_mkdir - Create a new directory in rpc_pipefs * @path: path from the rpc_pipefs root to the new directory - * @rpc_clnt: rpc client to associate with this directory + * @rpc_client: rpc client to associate with this directory * * This creates a directory at the given @path associated with * @rpc_clnt, which will contain a file named "info" with some basic @@ -695,7 +696,7 @@ rpc_mkdir(char *path, struct rpc_clnt *rpc_client) dentry = rpc_lookup_negative(path, &nd); if (IS_ERR(dentry)) return dentry; - dir = nd.dentry->d_inode; + dir = nd.path.dentry->d_inode; if ((error = __rpc_mkdir(dir, dentry)) != 0) goto err_dput; RPC_I(dentry->d_inode)->private = rpc_client; @@ -748,6 +749,7 @@ rpc_rmdir(struct dentry *dentry) * @private: private data to associate with the pipe, for the caller's use * @ops: operations defining the behavior of the pipe: upcall, downcall, * release_pipe, and destroy_msg. + * @flags: rpc_inode flags * * Data is made available for userspace to read by calls to * rpc_queue_upcall(). The actual reads will result in calls to diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index cfcade906a56..d5553b8179f9 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -124,7 +124,7 @@ EXPORT_SYMBOL_GPL(xprt_register_transport); /** * xprt_unregister_transport - unregister a transport implementation - * transport: transport to unregister + * @transport: transport to unregister * * Returns: * 0: transport successfully unregistered diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 3e321949e1dc..0598b229c11d 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -159,7 +159,8 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp, BUG_ON(sge_count >= 32); dprintk("svcrdma: RDMA_WRITE rmr=%x, to=%llx, xdr_off=%d, " "write_len=%d, xdr_sge=%p, sge_count=%d\n", - rmr, to, xdr_off, write_len, xdr_sge, sge_count); + rmr, (unsigned long long)to, xdr_off, + write_len, xdr_sge, sge_count); ctxt = svc_rdma_get_context(xprt); ctxt->count = 0; diff --git a/net/tipc/addr.h b/net/tipc/addr.h index e4bd5335e48d..3ba67e6ce03e 100644 --- a/net/tipc/addr.h +++ b/net/tipc/addr.h @@ -57,11 +57,6 @@ static inline int in_own_cluster(u32 addr) return !((addr ^ tipc_own_addr) >> 12); } -static inline int in_own_zone(u32 addr) -{ - return !((addr ^ tipc_own_addr) >> 24); -} - static inline int is_slave(u32 addr) { return addr & 0x800; diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index f910ed29d055..a2416fa6b906 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h @@ -74,19 +74,6 @@ extern char tipc_bclink_name[]; /** - * nmap_get - determine if node exists in a node map - */ - -static inline int tipc_nmap_get(struct node_map *nm_ptr, u32 node) -{ - int n = tipc_node(node); - int w = n / WSIZE; - int b = n % WSIZE; - - return nm_ptr->map[w] & (1 << b); -} - -/** * nmap_add - add a node to a node map */ diff --git a/net/tipc/msg.h b/net/tipc/msg.h index ce2659836374..e9ef6df26562 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -663,11 +663,6 @@ static inline void msg_set_remote_node(struct tipc_msg *m, u32 a) msg_set_word(m, msg_hdr_sz(m)/4, a); } -static inline int msg_dataoctet(struct tipc_msg *m, u32 pos) -{ - return(msg_data(m)[pos + 4] != 0); -} - static inline void msg_set_dataoctet(struct tipc_msg *m, u32 pos) { msg_data(m)[pos + 4] = 1; diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 24ddfd2ca38b..22909036b9bc 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -71,9 +71,9 @@ struct tipc_sock { static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf); static void wakeupdispatch(struct tipc_port *tport); -static struct proto_ops packet_ops; -static struct proto_ops stream_ops; -static struct proto_ops msg_ops; +static const struct proto_ops packet_ops; +static const struct proto_ops stream_ops; +static const struct proto_ops msg_ops; static struct proto tipc_proto; @@ -1615,7 +1615,7 @@ static int getsockopt(struct socket *sock, * Protocol switches for the various types of TIPC sockets */ -static struct proto_ops msg_ops = { +static const struct proto_ops msg_ops = { .owner = THIS_MODULE, .family = AF_TIPC, .release = release, @@ -1636,7 +1636,7 @@ static struct proto_ops msg_ops = { .sendpage = sock_no_sendpage }; -static struct proto_ops packet_ops = { +static const struct proto_ops packet_ops = { .owner = THIS_MODULE, .family = AF_TIPC, .release = release, @@ -1657,7 +1657,7 @@ static struct proto_ops packet_ops = { .sendpage = sock_no_sendpage }; -static struct proto_ops stream_ops = { +static const struct proto_ops stream_ops = { .owner = THIS_MODULE, .family = AF_TIPC, .release = release, @@ -1678,7 +1678,7 @@ static struct proto_ops stream_ops = { .sendpage = sock_no_sendpage }; -static struct net_proto_family tipc_family_ops = { +static const struct net_proto_family tipc_family_ops = { .owner = THIS_MODULE, .family = AF_TIPC, .create = tipc_create diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index eea75888805e..b8788fd5e3c6 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -718,16 +718,16 @@ static struct sock *unix_find_other(struct net *net, goto put_fail; err = -ECONNREFUSED; - if (!S_ISSOCK(nd.dentry->d_inode->i_mode)) + if (!S_ISSOCK(nd.path.dentry->d_inode->i_mode)) goto put_fail; - u=unix_find_socket_byinode(net, nd.dentry->d_inode); + u = unix_find_socket_byinode(net, nd.path.dentry->d_inode); if (!u) goto put_fail; if (u->sk_type == type) - touch_atime(nd.mnt, nd.dentry); + touch_atime(nd.path.mnt, nd.path.dentry); - path_release(&nd); + path_put(&nd.path); err=-EPROTOTYPE; if (u->sk_type != type) { @@ -748,7 +748,7 @@ static struct sock *unix_find_other(struct net *net, return u; put_fail: - path_release(&nd); + path_put(&nd.path); fail: *error=err; return NULL; @@ -819,12 +819,12 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) */ mode = S_IFSOCK | (SOCK_INODE(sock)->i_mode & ~current->fs->umask); - err = vfs_mknod(nd.dentry->d_inode, dentry, mode, 0); + err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, 0); if (err) goto out_mknod_dput; - mutex_unlock(&nd.dentry->d_inode->i_mutex); - dput(nd.dentry); - nd.dentry = dentry; + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + dput(nd.path.dentry); + nd.path.dentry = dentry; addr->hash = UNIX_HASH_SIZE; } @@ -842,8 +842,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) list = &unix_socket_table[addr->hash]; } else { list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)]; - u->dentry = nd.dentry; - u->mnt = nd.mnt; + u->dentry = nd.path.dentry; + u->mnt = nd.path.mnt; } err = 0; @@ -861,8 +861,8 @@ out: out_mknod_dput: dput(dentry); out_mknod_unlock: - mutex_unlock(&nd.dentry->d_inode->i_mutex); - path_release(&nd); + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); out_mknod_parent: if (err==-EEXIST) err=-EADDRINUSE; diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig index 8f9dbec319be..9201ef8ad90e 100644 --- a/net/xfrm/Kconfig +++ b/net/xfrm/Kconfig @@ -38,7 +38,7 @@ config XFRM_MIGRATE config XFRM_STATISTICS bool "Transformation statistics (EXPERIMENTAL)" - depends on XFRM && PROC_FS && EXPERIMENTAL + depends on INET && XFRM && PROC_FS && EXPERIMENTAL ---help--- This statistics is not a SNMP/MIB specification but shows statistics about transformation error (or almost error) factor diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index 6cc15250de69..8aa6440d689f 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c @@ -399,6 +399,23 @@ static struct xfrm_algo_desc ealg_list[] = { .sadb_alg_maxbits = 256 } }, +{ + .name = "rfc3686(ctr(aes))", + + .uinfo = { + .encr = { + .blockbits = 128, + .defkeybits = 160, /* 128-bit key + 32-bit nonce */ + } + }, + + .desc = { + .sadb_alg_id = SADB_X_EALG_AESCTR, + .sadb_alg_ivlen = 8, + .sadb_alg_minbits = 128, + .sadb_alg_maxbits = 256 + } +}, }; static struct xfrm_algo_desc calg_list[] = { diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 4d6ebc633a94..62188c6a06dd 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -109,7 +109,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) if (encap_type < 0) { async = 1; x = xfrm_input_state(skb); - seq = XFRM_SKB_CB(skb)->seq; + seq = XFRM_SKB_CB(skb)->seq.input; goto resume; } @@ -175,7 +175,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) spin_unlock(&x->lock); - XFRM_SKB_CB(skb)->seq = seq; + XFRM_SKB_CB(skb)->seq.input = seq; nexthdr = x->type->input(x, skb); diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index fc690368325f..569d377932c4 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -62,7 +62,7 @@ static int xfrm_output_one(struct sk_buff *skb, int err) } if (x->type->flags & XFRM_TYPE_REPLAY_PROT) { - XFRM_SKB_CB(skb)->seq = ++x->replay.oseq; + XFRM_SKB_CB(skb)->seq.output = ++x->replay.oseq; if (unlikely(x->replay.oseq == 0)) { XFRM_INC_STATS(LINUX_MIB_XFRMOUTSTATESEQERROR); x->replay.oseq--; diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 78338079b7f5..f971ca5645f8 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1105,6 +1105,7 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, return xp; error: *errp = err; + xp->dead = 1; xfrm_policy_destroy(xp); return NULL; } |