summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/9p/Makefile1
-rw-r--r--net/9p/client.c161
-rw-r--r--net/9p/fcprint.c4
-rw-r--r--net/9p/mod.c9
-rw-r--r--net/9p/mux.c1060
-rw-r--r--net/9p/trans_fd.c1103
-rw-r--r--net/9p/trans_virtio.c355
-rw-r--r--net/9p/util.c20
-rw-r--r--net/Kconfig2
-rw-r--r--net/can/af_can.c45
-rw-r--r--net/can/raw.c24
-rw-r--r--net/core/flow.c6
-rw-r--r--net/decnet/dn_route.c2
-rw-r--r--net/ipv4/igmp.c13
-rw-r--r--net/ipv4/ipvs/ip_vs_wrr.c3
-rw-r--r--net/ipv4/netfilter/nf_nat_core.c6
-rw-r--r--net/ipv4/route.c2
-rw-r--r--net/ipv6/route.c4
-rw-r--r--net/iucv/af_iucv.c27
-rw-r--r--net/iucv/iucv.c4
-rw-r--r--net/key/af_key.c117
-rw-r--r--net/mac80211/Kconfig1
-rw-r--r--net/netfilter/nf_conntrack_extend.c3
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c32
-rw-r--r--net/netfilter/xt_iprange.c3
-rw-r--r--net/rxrpc/af_rxrpc.c6
-rw-r--r--net/sched/cls_flow.c17
-rw-r--r--net/sched/em_meta.c18
-rw-r--r--net/sched/ematch.c8
-rw-r--r--net/sched/sch_htb.c13
-rw-r--r--net/sctp/associola.c14
-rw-r--r--net/sctp/auth.c8
-rw-r--r--net/sctp/bind_addr.c8
-rw-r--r--net/sctp/chunk.c8
-rw-r--r--net/sctp/command.c8
-rw-r--r--net/sctp/debug.c12
-rw-r--r--net/sctp/endpointola.c12
-rw-r--r--net/sctp/input.c8
-rw-r--r--net/sctp/inqueue.c8
-rw-r--r--net/sctp/ipv6.c8
-rw-r--r--net/sctp/objcnt.c93
-rw-r--r--net/sctp/output.c8
-rw-r--r--net/sctp/outqueue.c12
-rw-r--r--net/sctp/primitive.c8
-rw-r--r--net/sctp/proc.c31
-rw-r--r--net/sctp/protocol.c8
-rw-r--r--net/sctp/sm_make_chunk.c9
-rw-r--r--net/sctp/sm_sideeffect.c8
-rw-r--r--net/sctp/sm_statefuns.c10
-rw-r--r--net/sctp/sm_statetable.c8
-rw-r--r--net/sctp/socket.c17
-rw-r--r--net/sctp/ssnmap.c8
-rw-r--r--net/sctp/sysctl.c8
-rw-r--r--net/sctp/transport.c8
-rw-r--r--net/sctp/tsnmap.c8
-rw-r--r--net/sctp/ulpevent.c7
-rw-r--r--net/sctp/ulpqueue.c43
-rw-r--r--net/tipc/addr.h5
-rw-r--r--net/tipc/bcast.h13
-rw-r--r--net/tipc/msg.h5
-rw-r--r--net/tipc/socket.c14
-rw-r--r--net/xfrm/xfrm_algo.c17
62 files changed, 1874 insertions, 1637 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(&current->sighand->siglock, flags);
- recalc_sigpending();
- spin_unlock_irqrestore(&current->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(&current->sighand->siglock, flags);
+ recalc_sigpending();
+ spin_unlock_irqrestore(&current->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/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/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/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/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/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/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/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..b3ac85e808ac 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3734,21 +3734,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 +3750,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 +3843,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 +3858,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..202d7fa09483 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_CLOSE)
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_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/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/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/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[] = {