* [PATCH 25/29] nfs: remove mempools
From: Peter Zijlstra @ 2007-12-14 15:39 UTC (permalink / raw)
To: Linus Torvalds, Andrew Morton, linux-kernel, linux-mm, netdev,
trond.myklebust
Cc: Peter Zijlstra
In-Reply-To: <20071214153907.770251000@chello.nl>
[-- Attachment #1: nfs-no-mempool.patch --]
[-- Type: text/plain, Size: 4919 bytes --]
With the introduction of the shared dirty page accounting in .19, NFS should
not be able to surpise the VM with all dirty pages. Thus it should always be
able to free some memory. Hence no more need for mempools.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
---
fs/nfs/read.c | 15 +++------------
fs/nfs/write.c | 27 +++++----------------------
2 files changed, 8 insertions(+), 34 deletions(-)
Index: linux-2.6/fs/nfs/read.c
===================================================================
--- linux-2.6.orig/fs/nfs/read.c
+++ linux-2.6/fs/nfs/read.c
@@ -33,13 +33,10 @@ static const struct rpc_call_ops nfs_rea
static const struct rpc_call_ops nfs_read_full_ops;
static struct kmem_cache *nfs_rdata_cachep;
-static mempool_t *nfs_rdata_mempool;
-
-#define MIN_POOL_READ (32)
struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
{
- struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_NOFS);
+ struct nfs_read_data *p = kmem_cache_alloc(nfs_rdata_cachep, GFP_NOFS);
if (p) {
memset(p, 0, sizeof(*p));
@@ -50,7 +47,7 @@ struct nfs_read_data *nfs_readdata_alloc
else {
p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
if (!p->pagevec) {
- mempool_free(p, nfs_rdata_mempool);
+ kmem_cache_free(nfs_rdata_cachep, p);
p = NULL;
}
}
@@ -63,7 +60,7 @@ static void nfs_readdata_rcu_free(struct
struct nfs_read_data *p = container_of(head, struct nfs_read_data, task.u.tk_rcu);
if (p && (p->pagevec != &p->page_array[0]))
kfree(p->pagevec);
- mempool_free(p, nfs_rdata_mempool);
+ kmem_cache_free(nfs_rdata_cachep, p);
}
static void nfs_readdata_free(struct nfs_read_data *rdata)
@@ -597,16 +594,10 @@ int __init nfs_init_readpagecache(void)
if (nfs_rdata_cachep == NULL)
return -ENOMEM;
- nfs_rdata_mempool = mempool_create_slab_pool(MIN_POOL_READ,
- nfs_rdata_cachep);
- if (nfs_rdata_mempool == NULL)
- return -ENOMEM;
-
return 0;
}
void nfs_destroy_readpagecache(void)
{
- mempool_destroy(nfs_rdata_mempool);
kmem_cache_destroy(nfs_rdata_cachep);
}
Index: linux-2.6/fs/nfs/write.c
===================================================================
--- linux-2.6.orig/fs/nfs/write.c
+++ linux-2.6/fs/nfs/write.c
@@ -28,9 +28,6 @@
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
-#define MIN_POOL_WRITE (32)
-#define MIN_POOL_COMMIT (4)
-
/*
* Local function declarations
*/
@@ -44,12 +41,10 @@ static const struct rpc_call_ops nfs_wri
static const struct rpc_call_ops nfs_commit_ops;
static struct kmem_cache *nfs_wdata_cachep;
-static mempool_t *nfs_wdata_mempool;
-static mempool_t *nfs_commit_mempool;
struct nfs_write_data *nfs_commit_alloc(void)
{
- struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS);
+ struct nfs_write_data *p = kmem_cache_alloc(nfs_wdata_cachep, GFP_NOFS);
if (p) {
memset(p, 0, sizeof(*p));
@@ -63,7 +58,7 @@ static void nfs_commit_rcu_free(struct r
struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu);
if (p && (p->pagevec != &p->page_array[0]))
kfree(p->pagevec);
- mempool_free(p, nfs_commit_mempool);
+ kmem_cache_free(nfs_wdata_cachep, p);
}
void nfs_commit_free(struct nfs_write_data *wdata)
@@ -73,7 +68,7 @@ void nfs_commit_free(struct nfs_write_da
struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
{
- struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS);
+ struct nfs_write_data *p = kmem_cache_alloc(nfs_wdata_cachep, GFP_NOFS);
if (p) {
memset(p, 0, sizeof(*p));
@@ -84,7 +79,7 @@ struct nfs_write_data *nfs_writedata_all
else {
p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
if (!p->pagevec) {
- mempool_free(p, nfs_wdata_mempool);
+ kmem_cache_free(nfs_wdata_cachep, p);
p = NULL;
}
}
@@ -97,7 +92,7 @@ static void nfs_writedata_rcu_free(struc
struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu);
if (p && (p->pagevec != &p->page_array[0]))
kfree(p->pagevec);
- mempool_free(p, nfs_wdata_mempool);
+ kmem_cache_free(nfs_wdata_cachep, p);
}
static void nfs_writedata_free(struct nfs_write_data *wdata)
@@ -1474,16 +1469,6 @@ int __init nfs_init_writepagecache(void)
if (nfs_wdata_cachep == NULL)
return -ENOMEM;
- nfs_wdata_mempool = mempool_create_slab_pool(MIN_POOL_WRITE,
- nfs_wdata_cachep);
- if (nfs_wdata_mempool == NULL)
- return -ENOMEM;
-
- nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT,
- nfs_wdata_cachep);
- if (nfs_commit_mempool == NULL)
- return -ENOMEM;
-
/*
* NFS congestion size, scale with available memory.
*
@@ -1509,8 +1494,6 @@ int __init nfs_init_writepagecache(void)
void nfs_destroy_writepagecache(void)
{
- mempool_destroy(nfs_commit_mempool);
- mempool_destroy(nfs_wdata_mempool);
kmem_cache_destroy(nfs_wdata_cachep);
}
--
^ permalink raw reply
* [PATCH 28/29] nfs: enable swap on NFS
From: Peter Zijlstra @ 2007-12-14 15:39 UTC (permalink / raw)
To: Linus Torvalds, Andrew Morton, linux-kernel, linux-mm, netdev,
trond.myklebust
Cc: Peter Zijlstra
In-Reply-To: <20071214153907.770251000@chello.nl>
[-- Attachment #1: nfs-swap_ops.patch --]
[-- Type: text/plain, Size: 10831 bytes --]
Implement all the new swapfile a_ops for NFS. This will set the NFS socket to
SOCK_MEMALLOC and run socket reconnect under PF_MEMALLOC as well as reset
SOCK_MEMALLOC before engaging the protocol ->connect() method.
PF_MEMALLOC should allow the allocation of struct socket and related objects
and the early (re)setting of SOCK_MEMALLOC should allow us to receive the
packets required for the TCP connection buildup.
(swapping continues over a server reset during heavy network traffic)
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
---
fs/Kconfig | 18 ++++++++++++
fs/nfs/file.c | 12 ++++++++
fs/nfs/write.c | 19 +++++++++++++
include/linux/nfs_fs.h | 2 +
include/linux/sunrpc/xprt.h | 5 ++-
net/sunrpc/sched.c | 9 ++++--
net/sunrpc/xprtsock.c | 63 ++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 125 insertions(+), 3 deletions(-)
Index: linux-2.6/fs/nfs/file.c
===================================================================
--- linux-2.6.orig/fs/nfs/file.c
+++ linux-2.6/fs/nfs/file.c
@@ -371,6 +371,13 @@ static int nfs_launder_page(struct page
return nfs_wb_page(page_file_mapping(page)->host, page);
}
+#ifdef CONFIG_NFS_SWAP
+static int nfs_swapfile(struct address_space *mapping, int enable)
+{
+ return xs_swapper(NFS_CLIENT(mapping->host)->cl_xprt, enable);
+}
+#endif
+
const struct address_space_operations nfs_file_aops = {
.readpage = nfs_readpage,
.readpages = nfs_readpages,
@@ -385,6 +392,11 @@ const struct address_space_operations nf
.direct_IO = nfs_direct_IO,
#endif
.launder_page = nfs_launder_page,
+#ifdef CONFIG_NFS_SWAP
+ .swapfile = nfs_swapfile,
+ .swap_out = nfs_swap_out,
+ .swap_in = nfs_readpage,
+#endif
};
static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
Index: linux-2.6/fs/nfs/write.c
===================================================================
--- linux-2.6.orig/fs/nfs/write.c
+++ linux-2.6/fs/nfs/write.c
@@ -365,6 +365,25 @@ int nfs_writepage(struct page *page, str
return ret;
}
+int nfs_swap_out(struct file *file, struct page *page,
+ struct writeback_control *wbc)
+{
+ struct nfs_open_context *ctx = nfs_file_open_context(file);
+ int status;
+
+ status = nfs_writepage_setup(ctx, page, 0, nfs_page_length(page));
+ if (status < 0) {
+ nfs_set_pageerror(page);
+ goto out;
+ }
+
+ status = nfs_writepage_locked(page, wbc);
+
+out:
+ unlock_page(page);
+ return status;
+}
+
static int nfs_writepages_callback(struct page *page, struct writeback_control *wbc, void *data)
{
int ret;
Index: linux-2.6/include/linux/nfs_fs.h
===================================================================
--- linux-2.6.orig/include/linux/nfs_fs.h
+++ linux-2.6/include/linux/nfs_fs.h
@@ -413,6 +413,8 @@ extern int nfs_flush_incompatible(struc
extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *);
extern void nfs_writedata_release(void *);
+extern int nfs_swap_out(struct file *file, struct page *page,
+ struct writeback_control *wbc);
/*
* Try to write back everything synchronously (but check the
Index: linux-2.6/fs/Kconfig
===================================================================
--- linux-2.6.orig/fs/Kconfig
+++ linux-2.6/fs/Kconfig
@@ -1692,6 +1692,18 @@ config NFS_DIRECTIO
causes open() to return EINVAL if a file residing in NFS is
opened with the O_DIRECT flag.
+config NFS_SWAP
+ bool "Provide swap over NFS support"
+ default n
+ depends on NFS_FS
+ select SUNRPC_SWAP
+ help
+ This option enables swapon to work on files located on NFS mounts.
+
+ For more details, see Documentation/vm_deadlock.txt
+
+ If unsure, say N.
+
config NFSD
tristate "NFS server support"
depends on INET
@@ -1835,6 +1847,12 @@ config SUNRPC_BIND34
If unsure, say N to get traditional behavior (version 2 rpcbind
requests only).
+config SUNRPC_SWAP
+ def_bool n
+ depends on SUNRPC
+ select NETVM
+ select SWAP_FILE
+
config RPCSEC_GSS_KRB5
tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
depends on SUNRPC && EXPERIMENTAL
Index: linux-2.6/include/linux/sunrpc/xprt.h
===================================================================
--- linux-2.6.orig/include/linux/sunrpc/xprt.h
+++ linux-2.6/include/linux/sunrpc/xprt.h
@@ -143,7 +143,9 @@ struct rpc_xprt {
unsigned int max_reqs; /* total slots */
unsigned long state; /* transport state */
unsigned char shutdown : 1, /* being shut down */
- resvport : 1; /* use a reserved port */
+ resvport : 1, /* use a reserved port */
+ swapper : 1; /* we're swapping over this
+ transport */
unsigned int bind_index; /* bind function index */
/*
@@ -246,6 +248,7 @@ struct rpc_rqst * xprt_lookup_rqst(struc
void xprt_complete_rqst(struct rpc_task *task, int copied);
void xprt_release_rqst_cong(struct rpc_task *task);
void xprt_disconnect(struct rpc_xprt *xprt);
+int xs_swapper(struct rpc_xprt *xprt, int enable);
/*
* Reserved bit positions in xprt->state
Index: linux-2.6/net/sunrpc/sched.c
===================================================================
--- linux-2.6.orig/net/sunrpc/sched.c
+++ linux-2.6/net/sunrpc/sched.c
@@ -761,7 +761,10 @@ struct rpc_buffer {
void *rpc_malloc(struct rpc_task *task, size_t size)
{
struct rpc_buffer *buf;
- gfp_t gfp = RPC_IS_SWAPPER(task) ? GFP_ATOMIC : GFP_NOWAIT;
+ gfp_t gfp = GFP_NOWAIT;
+
+ if (RPC_IS_SWAPPER(task))
+ gfp |= __GFP_MEMALLOC;
size += sizeof(struct rpc_buffer);
if (size <= RPC_BUFFER_MAXSIZE)
@@ -816,6 +819,8 @@ void rpc_init_task(struct rpc_task *task
atomic_set(&task->tk_count, 1);
task->tk_client = clnt;
task->tk_flags = flags;
+ if (clnt->cl_xprt->swapper)
+ task->tk_flags |= RPC_TASK_SWAPPER;
task->tk_ops = tk_ops;
if (tk_ops->rpc_call_prepare != NULL)
task->tk_action = rpc_prepare_task;
@@ -852,7 +857,7 @@ void rpc_init_task(struct rpc_task *task
static struct rpc_task *
rpc_alloc_task(void)
{
- return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOFS);
+ return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOIO);
}
static void rpc_free_task(struct rcu_head *rcu)
Index: linux-2.6/net/sunrpc/xprtsock.c
===================================================================
--- linux-2.6.orig/net/sunrpc/xprtsock.c
+++ linux-2.6/net/sunrpc/xprtsock.c
@@ -1397,6 +1397,9 @@ static void xs_udp_finish_connecting(str
transport->sock = sock;
transport->inet = sk;
+ if (xprt->swapper)
+ sk_set_memalloc(sk);
+
write_unlock_bh(&sk->sk_callback_lock);
}
xs_udp_do_set_buffer_size(xprt);
@@ -1414,11 +1417,15 @@ static void xs_udp_connect_worker4(struc
container_of(work, struct sock_xprt, connect_worker.work);
struct rpc_xprt *xprt = &transport->xprt;
struct socket *sock = transport->sock;
+ unsigned long pflags = current->flags;
int err, status = -EIO;
if (xprt->shutdown || !xprt_bound(xprt))
goto out;
+ if (xprt->swapper)
+ current->flags |= PF_MEMALLOC;
+
/* Start by resetting any existing state */
xs_close(xprt);
@@ -1441,6 +1448,7 @@ static void xs_udp_connect_worker4(struc
out:
xprt_wake_pending_tasks(xprt, status);
xprt_clear_connecting(xprt);
+ tsk_restore_flags(current, pflags, PF_MEMALLOC);
}
/**
@@ -1455,11 +1463,15 @@ static void xs_udp_connect_worker6(struc
container_of(work, struct sock_xprt, connect_worker.work);
struct rpc_xprt *xprt = &transport->xprt;
struct socket *sock = transport->sock;
+ unsigned long pflags = current->flags;
int err, status = -EIO;
if (xprt->shutdown || !xprt_bound(xprt))
goto out;
+ if (xprt->swapper)
+ current->flags |= PF_MEMALLOC;
+
/* Start by resetting any existing state */
xs_close(xprt);
@@ -1482,6 +1494,7 @@ static void xs_udp_connect_worker6(struc
out:
xprt_wake_pending_tasks(xprt, status);
xprt_clear_connecting(xprt);
+ tsk_restore_flags(current, pflags, PF_MEMALLOC);
}
/*
@@ -1541,6 +1554,9 @@ static int xs_tcp_finish_connecting(stru
write_unlock_bh(&sk->sk_callback_lock);
}
+ if (xprt->swapper)
+ sk_set_memalloc(transport->inet);
+
/* Tell the socket layer to start connecting... */
xprt->stat.connect_count++;
xprt->stat.connect_start = jiffies;
@@ -1559,11 +1575,15 @@ static void xs_tcp_connect_worker4(struc
container_of(work, struct sock_xprt, connect_worker.work);
struct rpc_xprt *xprt = &transport->xprt;
struct socket *sock = transport->sock;
+ unsigned long pflags = current->flags;
int err, status = -EIO;
if (xprt->shutdown || !xprt_bound(xprt))
goto out;
+ if (xprt->swapper)
+ current->flags |= PF_MEMALLOC;
+
if (!sock) {
/* start from scratch */
if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
@@ -1606,6 +1626,7 @@ out:
xprt_wake_pending_tasks(xprt, status);
out_clear:
xprt_clear_connecting(xprt);
+ tsk_restore_flags(current, pflags, PF_MEMALLOC);
}
/**
@@ -1620,11 +1641,15 @@ static void xs_tcp_connect_worker6(struc
container_of(work, struct sock_xprt, connect_worker.work);
struct rpc_xprt *xprt = &transport->xprt;
struct socket *sock = transport->sock;
+ unsigned long pflags = current->flags;
int err, status = -EIO;
if (xprt->shutdown || !xprt_bound(xprt))
goto out;
+ if (xprt->swapper)
+ current->flags |= PF_MEMALLOC;
+
if (!sock) {
/* start from scratch */
if ((err = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
@@ -1666,6 +1691,7 @@ out:
xprt_wake_pending_tasks(xprt, status);
out_clear:
xprt_clear_connecting(xprt);
+ tsk_restore_flags(current, pflags, PF_MEMALLOC);
}
/**
@@ -1985,6 +2011,43 @@ int init_socket_xprt(void)
return 0;
}
+#ifdef CONFIG_SUNRPC_SWAP
+#define RPC_BUF_RESERVE_PAGES \
+ kestimate_single(sizeof(struct rpc_rqst), GFP_KERNEL, RPC_MAX_SLOT_TABLE)
+#define RPC_RESERVE_PAGES (RPC_BUF_RESERVE_PAGES + TX_RESERVE_PAGES)
+
+/**
+ * xs_swapper - Tag this transport as being used for swap.
+ * @xprt: transport to tag
+ * @enable: enable/disable
+ *
+ */
+int xs_swapper(struct rpc_xprt *xprt, int enable)
+{
+ struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+ int err = 0;
+
+ if (enable) {
+ /*
+ * keep one extra sock reference so the reserve won't dip
+ * when the socket gets reconnected.
+ */
+ err = sk_adjust_memalloc(1, RPC_RESERVE_PAGES);
+ if (!err) {
+ sk_set_memalloc(transport->inet);
+ xprt->swapper = 1;
+ }
+ } else if (xprt->swapper) {
+ xprt->swapper = 0;
+ sk_clear_memalloc(transport->inet);
+ sk_adjust_memalloc(-1, -RPC_RESERVE_PAGES);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xs_swapper);
+#endif
+
/**
* cleanup_socket_xprt - remove xprtsock's sysctls, unregister
*
--
^ permalink raw reply
* Re: 2.6.24-rc5-mm1
From: David Miller @ 2007-12-14 19:26 UTC (permalink / raw)
To: herbert; +Cc: benjamin.thery, pierre.peiffer, akpm, linux-kernel, netdev
In-Reply-To: <20071214020807.GA12426@gondor.apana.org.au>
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Fri, 14 Dec 2007 10:08:07 +0800
> [UDP]: Move udp_stats_in6 into net/ipv4/udp.c
>
> Now that external users may increment the counters directly, we need to
> ensure that udp_stats_in6 is always available. Otherwise we'd either
> have to requrie the external users to be built as modules or ipv6 to be
> built-in.
>
> This isn't too bad because udp_stats_in6 is just a pair of pointers plus
> an EXPORT, e.g., just 40 (16 + 24) bytes on x86-64.
>
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Applied.
^ permalink raw reply
* Re: [PATCHES 0/3]: DCCP patches for 2.6.25
From: David Miller @ 2007-12-14 19:29 UTC (permalink / raw)
To: acme; +Cc: netdev, dccp
In-Reply-To: <1197596522-14600-1-git-send-email-acme@redhat.com>
From: Arnaldo Carvalho de Melo <acme@redhat.com>
Date: Thu, 13 Dec 2007 23:41:59 -0200
> Please consider pulling from:
>
> master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6.25
Pulled, but could you please reformat Gerrit's changelog entries in
the future? They have these 80+ long lines which are painful to read
in ascii email clients and in terminal output.
I'll do this by hand during my next rebase for this case, but I will
push back when I see it again in future pull requests.
^ permalink raw reply
* Re: [patch 1/4] Updates to nfsroot documentation
From: David Miller @ 2007-12-14 19:30 UTC (permalink / raw)
To: akpm; +Cc: netdev, apw, ak, horms
In-Reply-To: <200712140002.lBE02XWr025488@imap1.linux-foundation.org>
From: akpm@linux-foundation.org
Date: Thu, 13 Dec 2007 16:02:33 -0800
> From: Amos Waterland <apw@us.ibm.com>
>
> The difference between ip=off and ip=::::::off has been a cause of much
> confusion. Document how each behaves, and do not contradict ourselves by
> saying that "off" is the default when in fact "any" is the default and is
> descibed as being so lower in the file.
>
> Signed-off-by: Amos Waterland <apw@us.ibm.com>
> Cc: Simon Horman <horms@verge.net.au>
> Cc: Andi Kleen <ak@suse.de>
> Cc: "David S. Miller" <davem@davemloft.net>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Applied.
^ permalink raw reply
* Re: [patch 2/4] net: use mutex_is_locked() for ASSERT_RTNL()
From: David Miller @ 2007-12-14 19:30 UTC (permalink / raw)
To: akpm; +Cc: netdev
In-Reply-To: <200712140002.lBE02aGO025491@imap1.linux-foundation.org>
From: akpm@linux-foundation.org
Date: Thu, 13 Dec 2007 16:02:36 -0800
> From: Andrew Morton <akpm@linux-foundation.org>
>
> ASSERT_RTNL() uses mutex_trylock(), but it's better to use mutex_is_locked().
>
> Make that change, and remove rtnl_trylock() altogether.
>
> (not tested yet!)
>
> Cc: "David S. Miller" <davem@davemloft.net>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
NACK, as explained please remove this until the replacement
doesn't remove valid checks which are done currently.
^ permalink raw reply
* Re: [patch 3/4] tipc: fix semaphore handling
From: David Miller @ 2007-12-14 19:31 UTC (permalink / raw)
To: akpm; +Cc: netdev, allan.stephens, jon.maloy, kjwinchester, per.liden,
stable
In-Reply-To: <200712140002.lBE02b3G025494@imap1.linux-foundation.org>
From: akpm@linux-foundation.org
Date: Thu, 13 Dec 2007 16:02:36 -0800
> From: Andrew Morton <akpm@linux-foundation.org>
>
> As noted by Kevin, tipc's release() does down_interruptible() and ignores the
> return value. So if signal_pending() we'll end up doing up() on a non-downed
> semaphore. Fix.
>
> Cc: Kevin Winchester <kjwinchester@gmail.com>
> Cc: Per Liden <per.liden@ericsson.com>
> Cc: Jon Maloy <jon.maloy@ericsson.com>
> Cc: Allan Stephens <allan.stephens@windriver.com>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: <stable@kernel.org>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This is already in my net-2.6 tree, but thanks for resubmitting
anyways :)
^ permalink raw reply
* Re: [patch 4/4] PPP synchronous tty: convert dead_sem to completion
From: David Miller @ 2007-12-14 19:33 UTC (permalink / raw)
To: akpm; +Cc: netdev, matthias.kaehlcke, paulus
In-Reply-To: <200712140002.lBE02cF7025497@imap1.linux-foundation.org>
From: akpm@linux-foundation.org
Date: Thu, 13 Dec 2007 16:02:37 -0800
> From: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
>
> PPP synchronous tty channel driver: convert the semaphore dead_sem to a
> completion
>
> Signed-off-by: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
> Cc: Paul Mackerras <paulus@samba.org>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Applied to net-2.6.25, thanks.
^ permalink raw reply
* Re: [PATCH][XFRM] Fix potential race vs xfrm_state(only)_find and xfrm_hash_resize.
From: David Miller @ 2007-12-14 19:39 UTC (permalink / raw)
To: xemul; +Cc: herbert, netdev, devel
In-Reply-To: <47610FCE.2000100@openvz.org>
From: Pavel Emelyanov <xemul@openvz.org>
Date: Thu, 13 Dec 2007 13:56:14 +0300
> The _find calls calculate the hash value using the
> xfrm_state_hmask, without the xfrm_state_lock. But the
> value of this mask can change in the _resize call under
> the state_lock, so we risk to fail in finding the desired
> entry in hash.
>
> I think, that the hash value is better to calculate
> under the state lock.
>
> Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Thanks for the bug fix.
I know why I coded it this way, I wanted to give GCC more
room to schedule the loads away from the uses in the hash
calculation.
Once you cram it after the spin lock acquire, it can't load unrelated
values earlier to soften the load/use cost on cache misses.
Of course it's invalid because the hash mask can change as you
noticed.
I wish there was a way to conditionally clobber memory, then we could
tell GCC exactly what memory objects are protected by the lock and
thus help in situations like this so much.
^ permalink raw reply
* [PATCH 2/2] ixgb: enable sun hardware support for broadcom phy
From: Auke Kok @ 2007-12-14 19:48 UTC (permalink / raw)
To: jeff; +Cc: netdev, auke-jan.h.kok, jesse.brandeburg, matheos.worku
In-Reply-To: <20071214194829.15478.2510.stgit@localhost.localdomain>
From: Matheos Worku <matheos.worku@sun.com>
Implement support for a SUN-specific PHY.
SUN provides a modified 82597-based board with their own
PHY that works with very little modification to the code. This
patch implements this new PHY which is identified by the
subvendor device ID. The device ID of the adapter remains
the same.
Signed-off-by: Matheos Worku <matheos.worku@sun.com>
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---
drivers/net/ixgb/ixgb_hw.c | 82 +++++++++++++++++++++++++++++++++++++++++-
drivers/net/ixgb/ixgb_hw.h | 3 +-
drivers/net/ixgb/ixgb_ids.h | 4 ++
drivers/net/ixgb/ixgb_main.c | 10 +++--
4 files changed, 91 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c
index 2c6367a..80a8b98 100644
--- a/drivers/net/ixgb/ixgb_hw.c
+++ b/drivers/net/ixgb/ixgb_hw.c
@@ -45,6 +45,8 @@ static boolean_t ixgb_link_reset(struct ixgb_hw *hw);
static void ixgb_optics_reset(struct ixgb_hw *hw);
+static void ixgb_optics_reset_bcm(struct ixgb_hw *hw);
+
static ixgb_phy_type ixgb_identify_phy(struct ixgb_hw *hw);
static void ixgb_clear_hw_cntrs(struct ixgb_hw *hw);
@@ -90,10 +92,20 @@ static uint32_t ixgb_mac_reset(struct ixgb_hw *hw)
ASSERT(!(ctrl_reg & IXGB_CTRL0_RST));
#endif
- if (hw->phy_type == ixgb_phy_type_txn17401) {
- ixgb_optics_reset(hw);
+ if (hw->subsystem_vendor_id == SUN_SUBVENDOR_ID) {
+ ctrl_reg = /* Enable interrupt from XFP and SerDes */
+ IXGB_CTRL1_GPI0_EN |
+ IXGB_CTRL1_SDP6_DIR |
+ IXGB_CTRL1_SDP7_DIR |
+ IXGB_CTRL1_SDP6 |
+ IXGB_CTRL1_SDP7;
+ IXGB_WRITE_REG(hw, CTRL1, ctrl_reg);
+ ixgb_optics_reset_bcm(hw);
}
+ if (hw->phy_type == ixgb_phy_type_txn17401)
+ ixgb_optics_reset(hw);
+
return ctrl_reg;
}
@@ -253,6 +265,10 @@ ixgb_identify_phy(struct ixgb_hw *hw)
break;
}
+ /* update phy type for sun specific board */
+ if (hw->subsystem_vendor_id == SUN_SUBVENDOR_ID)
+ phy_type = ixgb_phy_type_bcm;
+
return (phy_type);
}
@@ -1225,3 +1241,65 @@ ixgb_optics_reset(struct ixgb_hw *hw)
return;
}
+
+/******************************************************************************
+ * Resets the 10GbE optics module for Sun variant NIC.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+
+#define IXGB_BCM8704_USER_PMD_TX_CTRL_REG 0xC803
+#define IXGB_BCM8704_USER_PMD_TX_CTRL_REG_VAL 0x0164
+#define IXGB_BCM8704_USER_CTRL_REG 0xC800
+#define IXGB_BCM8704_USER_CTRL_REG_VAL 0x7FBF
+#define IXGB_BCM8704_USER_DEV3_ADDR 0x0003
+#define IXGB_SUN_PHY_ADDRESS 0x0000
+#define IXGB_SUN_PHY_RESET_DELAY 305
+
+static void
+ixgb_optics_reset_bcm(struct ixgb_hw *hw)
+{
+ u32 ctrl = IXGB_READ_REG(hw, CTRL0);
+ ctrl &= ~IXGB_CTRL0_SDP2;
+ ctrl |= IXGB_CTRL0_SDP3;
+ IXGB_WRITE_REG(hw, CTRL0, ctrl);
+
+ /* SerDes needs extra delay */
+ msleep(IXGB_SUN_PHY_RESET_DELAY);
+
+ /* Broadcom 7408L configuration */
+ /* Reference clock config */
+ ixgb_write_phy_reg(hw,
+ IXGB_BCM8704_USER_PMD_TX_CTRL_REG,
+ IXGB_SUN_PHY_ADDRESS,
+ IXGB_BCM8704_USER_DEV3_ADDR,
+ IXGB_BCM8704_USER_PMD_TX_CTRL_REG_VAL);
+ /* we must read the registers twice */
+ ixgb_read_phy_reg(hw,
+ IXGB_BCM8704_USER_PMD_TX_CTRL_REG,
+ IXGB_SUN_PHY_ADDRESS,
+ IXGB_BCM8704_USER_DEV3_ADDR);
+ ixgb_read_phy_reg(hw,
+ IXGB_BCM8704_USER_PMD_TX_CTRL_REG,
+ IXGB_SUN_PHY_ADDRESS,
+ IXGB_BCM8704_USER_DEV3_ADDR);
+
+ ixgb_write_phy_reg(hw,
+ IXGB_BCM8704_USER_CTRL_REG,
+ IXGB_SUN_PHY_ADDRESS,
+ IXGB_BCM8704_USER_DEV3_ADDR,
+ IXGB_BCM8704_USER_CTRL_REG_VAL);
+ ixgb_read_phy_reg(hw,
+ IXGB_BCM8704_USER_CTRL_REG,
+ IXGB_SUN_PHY_ADDRESS,
+ IXGB_BCM8704_USER_DEV3_ADDR);
+ ixgb_read_phy_reg(hw,
+ IXGB_BCM8704_USER_CTRL_REG,
+ IXGB_SUN_PHY_ADDRESS,
+ IXGB_BCM8704_USER_DEV3_ADDR);
+
+ /* SerDes needs extra delay */
+ msleep(IXGB_SUN_PHY_RESET_DELAY);
+
+ return;
+}
diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h
index af56433..f4e0044 100644
--- a/drivers/net/ixgb/ixgb_hw.h
+++ b/drivers/net/ixgb/ixgb_hw.h
@@ -44,7 +44,8 @@ typedef enum {
ixgb_phy_type_g6005, /* 850nm, MM fiber, XPAK transceiver */
ixgb_phy_type_g6104, /* 1310nm, SM fiber, XPAK transceiver */
ixgb_phy_type_txn17201, /* 850nm, MM fiber, XPAK transceiver */
- ixgb_phy_type_txn17401 /* 1310nm, SM fiber, XENPAK transceiver */
+ ixgb_phy_type_txn17401, /* 1310nm, SM fiber, XENPAK transceiver */
+ ixgb_phy_type_bcm /* SUN specific board */
} ixgb_phy_type;
/* XPAK transceiver vendors, for the SR adapters */
diff --git a/drivers/net/ixgb/ixgb_ids.h b/drivers/net/ixgb/ixgb_ids.h
index 4376e7e..180d20e 100644
--- a/drivers/net/ixgb/ixgb_ids.h
+++ b/drivers/net/ixgb/ixgb_ids.h
@@ -35,7 +35,8 @@
#define INTEL_VENDOR_ID 0x8086
#define INTEL_SUBVENDOR_ID 0x8086
-
+#define SUN_VENDOR_ID 0x108E
+#define SUN_SUBVENDOR_ID 0x108E
#define IXGB_DEVICE_ID_82597EX 0x1048
#define IXGB_DEVICE_ID_82597EX_SR 0x1A48
@@ -46,6 +47,7 @@
#define IXGB_DEVICE_ID_82597EX_CX4 0x109E
#define IXGB_SUBDEVICE_ID_A00C 0xA00C
#define IXGB_SUBDEVICE_ID_A01C 0xA01C
+#define IXGB_SUBDEVICE_ID_7036 0x7036
#endif /* #ifndef _IXGB_IDS_H_ */
/* End of File */
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index bf9085f..af4d5d4 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -36,7 +36,7 @@ static char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
-#define DRV_VERSION "1.0.126-k2"DRIVERNAPI
+#define DRV_VERSION "1.0.126-k4"DRIVERNAPI
const char ixgb_driver_version[] = DRV_VERSION;
static const char ixgb_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
@@ -212,9 +212,11 @@ static void
ixgb_irq_enable(struct ixgb_adapter *adapter)
{
if(atomic_dec_and_test(&adapter->irq_sem)) {
- IXGB_WRITE_REG(&adapter->hw, IMS,
- IXGB_INT_RXT0 | IXGB_INT_RXDMT0 | IXGB_INT_TXDW |
- IXGB_INT_LSC);
+ u32 val = IXGB_INT_RXT0 | IXGB_INT_RXDMT0 |
+ IXGB_INT_TXDW | IXGB_INT_LSC;
+ if (adapter->hw.subsystem_vendor_id == SUN_SUBVENDOR_ID)
+ val |= IXGB_INT_GPI0;
+ IXGB_WRITE_REG(&adapter->hw, IMS, val);
IXGB_WRITE_FLUSH(&adapter->hw);
}
}
^ permalink raw reply related
* [PATCH 1/2] ixgb: make sure jumbos stay enabled after reset
From: Auke Kok @ 2007-12-14 19:48 UTC (permalink / raw)
To: jeff; +Cc: netdev, auke-jan.h.kok, jesse.brandeburg, matheos.worku
From: Matheos Worku <matheos.worku@sun.com>
Currently a device reset (ethtool -r ethX) would cause the
adapter to fall back to regular MTU sizes.
Signed-off-by: Matheos Worku <matheos.worku@sun.com>
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---
drivers/net/ixgb/ixgb_main.c | 16 ++++++++++++++--
1 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 3021234..bf9085f 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -320,10 +320,22 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog)
void
ixgb_reset(struct ixgb_adapter *adapter)
{
+ struct ixgb_hw *hw = &adapter->hw;
- ixgb_adapter_stop(&adapter->hw);
- if(!ixgb_init_hw(&adapter->hw))
+ ixgb_adapter_stop(hw);
+ if (!ixgb_init_hw(hw))
DPRINTK(PROBE, ERR, "ixgb_init_hw failed.\n");
+
+ /* restore frame size information */
+ IXGB_WRITE_REG(hw, MFS, hw->max_frame_size << IXGB_MFS_SHIFT);
+ if (hw->max_frame_size >
+ IXGB_MAX_ENET_FRAME_SIZE_WITHOUT_FCS + ENET_FCS_LENGTH) {
+ u32 ctrl0 = IXGB_READ_REG(hw, CTRL0);
+ if (!(ctrl0 & IXGB_CTRL0_JFE)) {
+ ctrl0 |= IXGB_CTRL0_JFE;
+ IXGB_WRITE_REG(hw, CTRL0, ctrl0);
+ }
+ }
}
/**
^ permalink raw reply related
* [PATCH net-2.6.25] Revert recent TCP work
From: Ilpo Järvinen @ 2007-12-14 20:14 UTC (permalink / raw)
To: David Miller, Andrew Morton
Cc: Cedric Le Goater, LKML, Netdev, Reuben Farrelly, Kamalesh Babulal,
Rik van Riel, Dhaval Giani
In-Reply-To: <Pine.LNX.4.64.0712140024360.12376@kivilampi-30.cs.helsinki.fi>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 43527 bytes --]
On Fri, 14 Dec 2007, Ilpo Järvinen wrote:
> So, I might soon prepare a revert patch for most of the questionable
> TCP parts and ask Dave to apply it (and drop them fully during next
> rebase) unless I suddently figure something out soon which explains
> all/most of the problems, then return to drawing board. ...As it seems
> that the cumulative ACK processing problem discovered later on (having
> rather cumbersome solution with skbs only) will make part of the work
> that's currently in net-2.6.25 quite useless/duplicate effort. But thanks
> anyway for reporting these.
Hi Dave,
Could you either drop my recent patches (+one fix to them from Herbert
Xu == "[TCP]: Fix crash in tcp_advance_send_head"), all mine after "[TCP]:
Abstract tp->highest_sack accessing & point to next skb" from net-2.6.25
or just apply the revert from below and do the removal during next rebase.
I think it could even be automated by something like this (untested):
for i in $(cat commits | cut -d ' ' -f 1); do git-rebase --onto $i^ $i; done
(I've attached the commits list).
I'll resend small bits that are still useful but get removed in this kind
of straightforward operation (I guess it's easier for you to track this
way and makes conflicts a non-problem).
...It was buggy as well, I've tried to Cc all bug reporters that I've
noticed so far... Related bugs include at least these cases:
These are completely removed by this revert:
__tcp_rb_insert
(__|)tcp_reset_fack_counts
May still trigger later due to other, genuine bugs:
tcp_sacktag_one (I'll rework & resend this soon)
tcp_fastretrans_alert (fackets_out trap)
BUG_TRAP(packets <= tp->packets_out); in tcp_mark_head_lost
--
i.
[PATCH net-2.6.25] Revert recent TCP work
It was recently discovered that there's yet another processing
aspect to consider related to cumulative ACK processing. This
solution wasn't enough to handle that but "(arguably) complex"
and intrusive changes were still necessary in addition to the
complexity this already introduced. Another approach is on the
drawing board.
This was somehow buggy as well, a lot of reports against it
were filed already :-), but hunting the cause doesn't seem so
beneficial anymore.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
---
include/linux/skbuff.h | 3 -
include/linux/tcp.h | 4 -
include/net/tcp.h | 362 ++++------------------------------------------
net/ipv4/tcp_input.c | 341 ++++++++++++++++++++-----------------------
net/ipv4/tcp_ipv4.c | 1 -
net/ipv4/tcp_minisocks.c | 1 -
net/ipv4/tcp_output.c | 13 +-
net/ipv6/tcp_ipv6.c | 1 -
8 files changed, 196 insertions(+), 530 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index f21fee6..c618fbf 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -18,7 +18,6 @@
#include <linux/compiler.h>
#include <linux/time.h>
#include <linux/cache.h>
-#include <linux/rbtree.h>
#include <asm/atomic.h>
#include <asm/types.h>
@@ -254,8 +253,6 @@ struct sk_buff {
struct sk_buff *next;
struct sk_buff *prev;
- struct rb_node rb;
-
struct sock *sk;
ktime_t tstamp;
struct net_device *dev;
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 56342c3..08027f1 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -174,7 +174,6 @@ struct tcp_md5sig {
#include <linux/skbuff.h>
#include <linux/dmaengine.h>
-#include <linux/rbtree.h>
#include <net/sock.h>
#include <net/inet_connection_sock.h>
#include <net/inet_timewait_sock.h>
@@ -321,9 +320,6 @@ struct tcp_sock {
u32 snd_cwnd_used;
u32 snd_cwnd_stamp;
- struct rb_root write_queue_rb;
- struct rb_root sacked_queue_rb;
- struct sk_buff_head sacked_queue;
struct sk_buff_head out_of_order_queue; /* Out of order segments go here */
u32 rcv_wnd; /* Current receiver window */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 5e6c433..5ec1cac 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -555,7 +555,6 @@ struct tcp_skb_cb {
__u32 seq; /* Starting sequence number */
__u32 end_seq; /* SEQ + FIN + SYN + datalen */
__u32 when; /* used to compute rtt's */
- unsigned int fack_count; /* speed up SACK processing */
__u8 flags; /* TCP header flags. */
/* NOTE: These must match up to the flags byte in a
@@ -1191,112 +1190,29 @@ static inline void tcp_put_md5sig_pool(void)
}
/* write queue abstraction */
-#define TCP_WQ_SACKED 1
-
-static inline struct sk_buff_head *__tcp_list_select(struct sock *sk, const int queue)
-{
- if (queue == TCP_WQ_SACKED)
- return &tcp_sk(sk)->sacked_queue;
- else
- return &sk->sk_write_queue;
-}
-
-static inline struct rb_root *__tcp_tree_select(struct sock *sk, const int tree)
-{
- if (tree == TCP_WQ_SACKED)
- return &tcp_sk(sk)->sacked_queue_rb;
- else
- return &tcp_sk(sk)->write_queue_rb;
-}
-
-/* All SACKed except S|R go to a separate skb space */
-static inline int __tcp_skb_queue_select(const struct sk_buff *skb)
-{
- if ((TCP_SKB_CB(skb)->sacked &
- (TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS)) ==
- TCPCB_SACKED_ACKED)
- return TCP_WQ_SACKED;
- else
- return 0;
-}
-
-static inline void tcp_write_queue_init(struct sock *sk)
-{
- tcp_sk(sk)->write_queue_rb = RB_ROOT;
- tcp_sk(sk)->sacked_queue_rb = RB_ROOT;
- skb_queue_head_init(&tcp_sk(sk)->sacked_queue);
-}
-
-static inline void __tcp_write_queue_purge(struct sock *sk, int queue)
+static inline void tcp_write_queue_purge(struct sock *sk)
{
struct sk_buff *skb;
- while ((skb = __skb_dequeue(__tcp_list_select(sk, queue))) != NULL)
+ while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL)
sk_stream_free_skb(sk, skb);
- *__tcp_tree_select(sk, queue) = RB_ROOT;
-}
-
-static inline void tcp_write_queue_purge(struct sock *sk)
-{
- __tcp_write_queue_purge(sk, 0);
- __tcp_write_queue_purge(sk, TCP_WQ_SACKED);
sk_stream_mem_reclaim(sk);
}
-static inline struct sk_buff *__tcp_write_queue_head(struct sock *sk, int queue)
-{
- struct sk_buff *skb = __tcp_list_select(sk, queue)->next;
- if (skb == (struct sk_buff *)__tcp_list_select(sk, queue))
- return NULL;
- return skb;
-}
-
static inline struct sk_buff *tcp_write_queue_head(struct sock *sk)
{
- return __tcp_write_queue_head(sk, 0);
-}
-
-/* FIXME, this should eventually vanish because callers likely benefit
- * from scanning the non-SACKed and SACKed spaces separately.
- */
-static inline struct sk_buff *tcp_real_queue_head(struct sock *sk)
-{
- struct sk_buff *skb, *sacked;
-
- skb = tcp_write_queue_head(sk);
- sacked = __tcp_write_queue_head(sk, TCP_WQ_SACKED);
-
- if (skb == NULL)
- return sacked;
- if (sacked == NULL)
- return skb;
-
- if (after(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(sacked)->seq))
- return sacked;
- return skb;
-}
-
-static inline struct sk_buff *__tcp_write_queue_tail(struct sock *sk, int queue)
-{
- struct sk_buff *skb = __tcp_list_select(sk, queue)->prev;
- if (skb == (struct sk_buff *)__tcp_list_select(sk, queue))
+ struct sk_buff *skb = sk->sk_write_queue.next;
+ if (skb == (struct sk_buff *) &sk->sk_write_queue)
return NULL;
return skb;
}
static inline struct sk_buff *tcp_write_queue_tail(struct sock *sk)
{
- return __tcp_write_queue_tail(sk, 0);
-}
-
-static inline int __tcp_write_queue_empty(struct sock *sk, int queue)
-{
- return skb_queue_empty(__tcp_list_select(sk, queue));
-}
-
-static inline int tcp_write_queue_empty(struct sock *sk)
-{
- return __tcp_write_queue_empty(sk, 0);
+ struct sk_buff *skb = sk->sk_write_queue.prev;
+ if (skb == (struct sk_buff *) &sk->sk_write_queue)
+ return NULL;
+ return skb;
}
static inline struct sk_buff *tcp_write_queue_next(struct sock *sk, struct sk_buff *skb)
@@ -1304,29 +1220,18 @@ static inline struct sk_buff *tcp_write_queue_next(struct sock *sk, struct sk_bu
return skb->next;
}
-static inline struct sk_buff *tcp_write_queue_prev(struct sock *sk, struct sk_buff *skb)
-{
- return skb->prev;
-}
-
-static inline int tcp_skb_adjacent(struct sock *sk, struct sk_buff *skb,
- struct sk_buff *next)
-{
- return TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(next)->seq;
-}
-
-#define tcp_for_write_queue(skb, sk, queue) \
- for (skb = __tcp_list_select(sk, queue)->next; \
- (skb != (struct sk_buff *)__tcp_list_select(sk, queue));\
+#define tcp_for_write_queue(skb, sk) \
+ for (skb = (sk)->sk_write_queue.next; \
+ (skb != (struct sk_buff *)&(sk)->sk_write_queue); \
skb = skb->next)
-#define tcp_for_write_queue_from(skb, sk, queue) \
- for (; (skb != (struct sk_buff *)__tcp_list_select(sk, queue));\
+#define tcp_for_write_queue_from(skb, sk) \
+ for (; (skb != (struct sk_buff *)&(sk)->sk_write_queue);\
skb = skb->next)
-#define tcp_for_write_queue_from_safe(skb, tmp, sk, queue) \
+#define tcp_for_write_queue_from_safe(skb, tmp, sk) \
for (tmp = skb->next; \
- (skb != (struct sk_buff *)__tcp_list_select(sk, queue));\
+ (skb != (struct sk_buff *)&(sk)->sk_write_queue); \
skb = tmp, tmp = skb->next)
static inline struct sk_buff *tcp_send_head(struct sock *sk)
@@ -1336,23 +1241,7 @@ static inline struct sk_buff *tcp_send_head(struct sock *sk)
static inline void tcp_advance_send_head(struct sock *sk, struct sk_buff *skb)
{
- struct sk_buff *prev = tcp_write_queue_prev(sk, skb);
- unsigned int fc = 0;
-
- if (prev == (struct sk_buff *)&sk->sk_write_queue)
- prev = NULL;
- else if (!tcp_skb_adjacent(sk, prev, skb))
- prev = NULL;
-
- if ((prev == NULL) && !__tcp_write_queue_empty(sk, TCP_WQ_SACKED))
- prev = __tcp_write_queue_tail(sk, TCP_WQ_SACKED);
-
- if (prev != NULL)
- fc = TCP_SKB_CB(prev)->fack_count + tcp_skb_pcount(prev);
-
- TCP_SKB_CB(skb)->fack_count = fc;
-
- sk->sk_send_head = tcp_write_queue_next(sk, skb);
+ sk->sk_send_head = skb->next;
if (sk->sk_send_head == (struct sk_buff *)&sk->sk_write_queue)
sk->sk_send_head = NULL;
}
@@ -1368,78 +1257,9 @@ static inline void tcp_init_send_head(struct sock *sk)
sk->sk_send_head = NULL;
}
-static inline struct sk_buff *__tcp_write_queue_find(struct rb_node *rb_node,
- __u32 seq)
-{
- struct sk_buff *skb = NULL;
-
- while (rb_node) {
- struct sk_buff *tmp = rb_entry(rb_node,struct sk_buff,rb);
- if (after(TCP_SKB_CB(tmp)->end_seq, seq)) {
- skb = tmp;
- if (!after(TCP_SKB_CB(tmp)->seq, seq))
- break;
- rb_node = rb_node->rb_left;
- } else
- rb_node = rb_node->rb_right;
-
- }
- return skb;
-}
-
-static inline struct sk_buff *tcp_write_queue_find(struct sock *sk, __u32 seq, int tree)
-{
- return __tcp_write_queue_find(__tcp_tree_select(sk, tree)->rb_node, seq);
-}
-
-/* Inserts skb into RB-tree root, prev node (ie., the skb before the inserted
- * one) is returned, which is available as a side-effect from parent of the
- * last rb_right edge. If no rb_right edge is walked, NULL is returned (tree
- * does not contain a smaller node).
- */
-static struct sk_buff *__tcp_rb_insert(struct sk_buff *skb,
- struct rb_root *root)
-{
- struct rb_node **rb_link, *rb_parent;
- struct sk_buff *prev = NULL;
- __u32 seq = TCP_SKB_CB(skb)->seq;
-
- rb_link = &root->rb_node;
- rb_parent = NULL;
- while (*rb_link) {
- struct sk_buff *tmp;
-
- rb_parent = *rb_link;
- tmp = rb_entry(rb_parent,struct sk_buff,rb);
- if (after(TCP_SKB_CB(tmp)->end_seq, seq)) {
- BUG_ON(!after(TCP_SKB_CB(tmp)->seq, seq));
- rb_link = &rb_parent->rb_left;
- } else {
- rb_link = &rb_parent->rb_right;
- prev = tmp;
- }
- }
- rb_link_node(&skb->rb, rb_parent, rb_link);
- rb_insert_color(&skb->rb, root);
-
- return prev;
-}
-
-static inline void tcp_rb_insert(struct sk_buff *skb, struct rb_root *root)
-{
- __tcp_rb_insert(skb, root);
-}
-
-static inline void tcp_rb_unlink(struct sk_buff *skb, struct rb_root *root)
-{
- rb_erase(&skb->rb, root);
-}
-
static inline void __tcp_add_write_queue_tail(struct sock *sk, struct sk_buff *skb)
{
- TCP_SKB_CB(skb)->fack_count = 0;
__skb_queue_tail(&sk->sk_write_queue, skb);
- tcp_rb_insert(skb, &tcp_sk(sk)->write_queue_rb);
}
static inline void tcp_add_write_queue_tail(struct sock *sk, struct sk_buff *skb)
@@ -1455,90 +1275,9 @@ static inline void tcp_add_write_queue_tail(struct sock *sk, struct sk_buff *skb
}
}
-/* This is only used for tcp_send_synack(), so the write queue should
- * be empty. If that stops being true, the fack_count assignment
- * will need to be more elaborate.
- */
static inline void __tcp_add_write_queue_head(struct sock *sk, struct sk_buff *skb)
{
- BUG_ON(!skb_queue_empty(&sk->sk_write_queue));
__skb_queue_head(&sk->sk_write_queue, skb);
- TCP_SKB_CB(skb)->fack_count = 0;
- tcp_rb_insert(skb, &tcp_sk(sk)->write_queue_rb);
-}
-
-/* An insert into the middle of the write queue causes the fack
- * counts in subsequent packets to become invalid, fix them up.
- *
- * FIXME, this definately could be improved!
- */
-static inline void tcp_reset_fack_counts(struct sock *sk, struct sk_buff *inskb)
-{
- struct sk_buff *prev;
- struct sk_buff *skb[2] = {NULL, NULL};
- int queue;
- unsigned int fc = 0;
-
- if (!before(TCP_SKB_CB(inskb)->seq, tcp_sk(sk)->snd_nxt))
- return;
-
- queue = __tcp_skb_queue_select(inskb);
- skb[queue] = inskb;
-
- prev = inskb->prev;
- if (inskb == __tcp_write_queue_head(sk, queue))
- prev = NULL;
-
- if (((prev != NULL) && !tcp_skb_adjacent(sk, prev, inskb)) ||
- ((prev == NULL) && (TCP_SKB_CB(inskb)->seq != tcp_sk(sk)->snd_una))) {
- int otherq = queue ^ TCP_WQ_SACKED;
-
- BUG_ON (__tcp_write_queue_empty(sk, otherq));
- prev = tcp_write_queue_find(sk, TCP_SKB_CB(inskb)->seq - 1,
- otherq);
- BUG_ON (prev == NULL || prev == tcp_send_head(sk));
- skb[otherq] = prev->next;
- }
-
- if (prev != NULL)
- fc = TCP_SKB_CB(prev)->fack_count + tcp_skb_pcount(prev);
-
- while (skb[queue] != (struct sk_buff *)__tcp_list_select(sk, queue)) {
- /* Lazy find for the other queue */
- if (skb[queue] == NULL) {
- skb[queue] = tcp_write_queue_find(sk, TCP_SKB_CB(prev)->seq,
- queue);
- if (skb[queue] == NULL)
- break;
- }
-
- BUG_ON((prev != NULL) && !tcp_skb_adjacent(sk, prev, skb[queue]));
-
- tcp_for_write_queue_from(skb[queue], sk, queue) {
- if ((prev != NULL) && !tcp_skb_adjacent(sk, prev, skb[queue]))
- break;
-
- if (!before(TCP_SKB_CB(skb[queue])->seq, tcp_sk(sk)->snd_nxt) ||
- TCP_SKB_CB(skb[queue])->fack_count == fc)
- return;
-
- TCP_SKB_CB(skb[queue])->fack_count = fc;
- fc += tcp_skb_pcount(skb[queue]);
-
- prev = skb[queue];
- }
-
- queue ^= TCP_WQ_SACKED;
- }
-}
-
-static inline void __tcp_insert_write_queue_after(struct sk_buff *skb,
- struct sk_buff *buff,
- struct sock *sk,
- int queue)
-{
- __skb_append(skb, buff, __tcp_list_select(sk, queue));
- tcp_rb_insert(buff, __tcp_tree_select(sk, queue));
}
/* Insert buff after skb on the write queue of sk. */
@@ -1546,74 +1285,36 @@ static inline void tcp_insert_write_queue_after(struct sk_buff *skb,
struct sk_buff *buff,
struct sock *sk)
{
- __tcp_insert_write_queue_after(skb, buff, sk, __tcp_skb_queue_select(buff));
- tcp_reset_fack_counts(sk, buff);
+ __skb_append(skb, buff, &sk->sk_write_queue);
}
-/* Insert new before skb on the write queue of sk.
- *
- * This is only used for tcp_mtu_probe() new send_head injection. If that
- * stops being true, needs to consider fack_counts and TCP_WQ_SACKED.
- */
-static inline void __tcp_insert_write_queue_before(struct sk_buff *new,
- struct sk_buff *skb,
- struct sock *sk)
+/* Insert skb between prev and next on the write queue of sk. */
+static inline void tcp_insert_write_queue_before(struct sk_buff *new,
+ struct sk_buff *skb,
+ struct sock *sk)
{
- BUG_ON(sk->sk_send_head != skb);
-
__skb_insert(new, skb->prev, skb, &sk->sk_write_queue);
- tcp_rb_insert(new, &tcp_sk(sk)->write_queue_rb);
- sk->sk_send_head = new;
-}
-static inline void tcp_unlink_write_queue(struct sk_buff *skb, struct sock *sk)
-{
- int queue = __tcp_skb_queue_select(skb);
-
- __skb_unlink(skb, __tcp_list_select(sk, queue));
- tcp_rb_unlink(skb, __tcp_tree_select(sk, queue));
+ if (sk->sk_send_head == skb)
+ sk->sk_send_head = new;
}
-/* Moves skb to queue part of the skb space, a bit fragile, call must be made
- * prior (important) sacked changes (= ->S and &~R)
- */
-static inline void tcp_write_queue_requeue(struct sk_buff *skb,
- struct sock *sk, int queue)
+static inline void tcp_unlink_write_queue(struct sk_buff *skb, struct sock *sk)
{
- struct sk_buff *prev;
-
- /* FIXME, most of hints are to be dropped soon... */
- if (tcp_sk(sk)->scoreboard_skb_hint == skb)
- tcp_sk(sk)->scoreboard_skb_hint = skb->next;
- if (tcp_sk(sk)->forward_skb_hint == skb)
- tcp_sk(sk)->forward_skb_hint = skb->next;
- /* ...These have related cnt */
- if (tcp_sk(sk)->lost_skb_hint == skb)
- tcp_sk(sk)->lost_skb_hint = NULL;
- if (tcp_sk(sk)->retransmit_skb_hint == skb)
- tcp_sk(sk)->retransmit_skb_hint = NULL;
-
- /* S|R must not be in SACKed space because of mark_lost_retrans walk */
- if ((queue == TCP_WQ_SACKED) &&
- (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS))
- return;
-
- tcp_unlink_write_queue(skb, sk);
-
- prev = __tcp_rb_insert(skb, __tcp_tree_select(sk, queue));
- if (prev == NULL)
- prev = (struct sk_buff *)__tcp_list_select(sk, queue);
- __skb_append(prev, skb, __tcp_list_select(sk, queue));
+ __skb_unlink(skb, &sk->sk_write_queue);
}
static inline int tcp_skb_is_last(const struct sock *sk,
const struct sk_buff *skb)
{
- BUG_ON(__tcp_skb_queue_select(skb) == TCP_WQ_SACKED);
-
return skb->next == (struct sk_buff *)&sk->sk_write_queue;
}
+static inline int tcp_write_queue_empty(struct sock *sk)
+{
+ return skb_queue_empty(&sk->sk_write_queue);
+}
+
/* Start sequence of the highest skb with SACKed bit, valid only if
* sacked > 0 or when the caller has ensured validity by itself.
*/
@@ -1628,9 +1329,6 @@ static inline u32 tcp_highest_sack_seq(struct tcp_sock *tp)
return TCP_SKB_CB(tp->highest_sack)->seq;
}
-/* This is somewhat dangerous now, because skb must still be in non-sacked
- * space
- */
static inline void tcp_advance_highest_sack(struct sock *sk, struct sk_buff *skb)
{
tcp_sk(sk)->highest_sack = tcp_skb_is_last(sk, skb) ? NULL :
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 218754b..616bbcb 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1072,7 +1072,7 @@ static void tcp_update_reordering(struct sock *sk, const int metric,
* the exact amount is rather hard to quantify. However, tp->max_window can
* be used as an exaggerated estimate.
*/
-static int tcp_is_sackblock_valid(struct tcp_sock *tp,
+static int tcp_is_sackblock_valid(struct tcp_sock *tp, int is_dsack,
u32 start_seq, u32 end_seq)
{
/* Too far in future, or reversed (interpretation is ambiguous) */
@@ -1089,16 +1089,10 @@ static int tcp_is_sackblock_valid(struct tcp_sock *tp,
if (after(start_seq, tp->snd_una))
return 1;
- return 0;
-}
-
-static int tcp_is_past_dsack_useful(struct tcp_sock *tp,
- u32 start_seq, u32 end_seq)
-{
- if (!tp->undo_marker)
+ if (!is_dsack || !tp->undo_marker)
return 0;
- /* ...Past D-SACK must reside below snd_una completely */
+ /* ...Then it's D-SACK, and must reside below snd_una completely */
if (!after(end_seq, tp->snd_una))
return 0;
@@ -1138,7 +1132,7 @@ static void tcp_mark_lost_retrans(struct sock *sk)
icsk->icsk_ca_state != TCP_CA_Recovery)
return;
- tcp_for_write_queue(skb, sk, 0) {
+ tcp_for_write_queue(skb, sk) {
u32 ack_seq = TCP_SKB_CB(skb)->ack_seq;
if (skb == tcp_send_head(sk))
@@ -1155,10 +1149,6 @@ static void tcp_mark_lost_retrans(struct sock *sk)
(tcp_is_fack(tp) ||
!before(received_upto,
ack_seq + tp->reordering * tp->mss_cache))) {
-
- if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)
- tcp_write_queue_requeue(skb, sk, TCP_WQ_SACKED);
-
TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
tp->retrans_out -= tcp_skb_pcount(skb);
@@ -1181,6 +1171,39 @@ static void tcp_mark_lost_retrans(struct sock *sk)
tp->lost_retrans_low = new_low_seq;
}
+static int tcp_check_dsack(struct tcp_sock *tp, struct sk_buff *ack_skb,
+ struct tcp_sack_block_wire *sp, int num_sacks,
+ u32 prior_snd_una)
+{
+ u32 start_seq_0 = ntohl(get_unaligned(&sp[0].start_seq));
+ u32 end_seq_0 = ntohl(get_unaligned(&sp[0].end_seq));
+ int dup_sack = 0;
+
+ if (before(start_seq_0, TCP_SKB_CB(ack_skb)->ack_seq)) {
+ dup_sack = 1;
+ tcp_dsack_seen(tp);
+ NET_INC_STATS_BH(LINUX_MIB_TCPDSACKRECV);
+ } else if (num_sacks > 1) {
+ u32 end_seq_1 = ntohl(get_unaligned(&sp[1].end_seq));
+ u32 start_seq_1 = ntohl(get_unaligned(&sp[1].start_seq));
+
+ if (!after(end_seq_0, end_seq_1) &&
+ !before(start_seq_0, start_seq_1)) {
+ dup_sack = 1;
+ tcp_dsack_seen(tp);
+ NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFORECV);
+ }
+ }
+
+ /* D-SACK for already forgotten data... Do dumb counting. */
+ if (dup_sack &&
+ !after(end_seq_0, prior_snd_una) &&
+ after(end_seq_0, tp->undo_marker))
+ tp->undo_retrans--;
+
+ return dup_sack;
+}
+
/* Check if skb is fully within the SACK block. In presence of GSO skbs,
* the incoming SACK may not exactly match but we can find smaller MSS
* aligned portion of it that matches. Therefore we might need to fragment
@@ -1214,15 +1237,11 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb,
}
static int tcp_sacktag_one(struct sk_buff *skb, struct sock *sk,
- int *reord, int dup_sack)
+ int *reord, int dup_sack, int fack_count)
{
struct tcp_sock *tp = tcp_sk(sk);
u8 sacked = TCP_SKB_CB(skb)->sacked;
int flag = 0;
- int fack_count;
-
- fack_count = TCP_SKB_CB(skb)->fack_count -
- TCP_SKB_CB(tcp_write_queue_head(sk))->fack_count;
/* Account D-SACK for retransmitted packet. */
if (dup_sack && (sacked & TCPCB_RETRANS)) {
@@ -1274,28 +1293,23 @@ static int tcp_sacktag_one(struct sk_buff *skb, struct sock *sk,
}
}
- fack_count += tcp_skb_pcount(skb);
- if (!before(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(tp))) {
- WARN_ON((fack_count <= tp->fackets_out) ||
- (fack_count > tp->packets_out));
-
- tcp_advance_highest_sack(sk, skb);
- tp->fackets_out = fack_count;
- } else
- WARN_ON(fack_count > tp->fackets_out);
-
- tcp_write_queue_requeue(skb, sk, TCP_WQ_SACKED);
-
TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED;
flag |= FLAG_DATA_SACKED;
tp->sacked_out += tcp_skb_pcount(skb);
+ fack_count += tcp_skb_pcount(skb);
+
/* Lost marker hint past SACKed? Tweak RFC3517 cnt */
if (!tcp_is_fack(tp) && (tp->lost_skb_hint != NULL) &&
before(TCP_SKB_CB(skb)->seq,
TCP_SKB_CB(tp->lost_skb_hint)->seq))
tp->lost_cnt_hint += tcp_skb_pcount(skb);
+ if (fack_count > tp->fackets_out)
+ tp->fackets_out = fack_count;
+
+ if (!before(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(tp)))
+ tcp_advance_highest_sack(sk, skb);
}
/* D-SACK. We can detect redundant retransmission in S|R and plain R
@@ -1303,8 +1317,6 @@ static int tcp_sacktag_one(struct sk_buff *skb, struct sock *sk,
* are accounted above as well.
*/
if (dup_sack && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)) {
- tcp_write_queue_requeue(skb, sk, TCP_WQ_SACKED);
-
TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
tp->retrans_out -= tcp_skb_pcount(skb);
tp->retransmit_skb_hint = NULL;
@@ -1314,14 +1326,14 @@ static int tcp_sacktag_one(struct sk_buff *skb, struct sock *sk,
}
static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk,
+ struct tcp_sack_block *next_dup,
u32 start_seq, u32 end_seq,
- int dup_sack, int *reord, int *flag,
- int queue)
+ int dup_sack_in, int *fack_count,
+ int *reord, int *flag)
{
- struct sk_buff *next;
-
- tcp_for_write_queue_from_safe(skb, next, sk, queue) {
+ tcp_for_write_queue_from(skb, sk) {
int in_sack = 0;
+ int dup_sack = dup_sack_in;
if (skb == tcp_send_head(sk))
break;
@@ -1330,12 +1342,24 @@ static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk,
if (!before(TCP_SKB_CB(skb)->seq, end_seq))
break;
- in_sack = tcp_match_skb_to_sack(sk, skb, start_seq, end_seq);
+ if ((next_dup != NULL) &&
+ before(TCP_SKB_CB(skb)->seq, next_dup->end_seq)) {
+ in_sack = tcp_match_skb_to_sack(sk, skb,
+ next_dup->start_seq,
+ next_dup->end_seq);
+ if (in_sack > 0)
+ dup_sack = 1;
+ }
+
+ if (in_sack <= 0)
+ in_sack = tcp_match_skb_to_sack(sk, skb, start_seq, end_seq);
if (unlikely(in_sack < 0))
break;
if (in_sack)
- *flag |= tcp_sacktag_one(skb, sk, reord, dup_sack);
+ *flag |= tcp_sacktag_one(skb, sk, reord, dup_sack, *fack_count);
+
+ *fack_count += tcp_skb_pcount(skb);
}
return skb;
}
@@ -1343,72 +1367,37 @@ static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk,
/* Avoid all extra work that is being done by sacktag while walking in
* a normal way
*/
-static struct sk_buff *tcp_sacktag_skip(struct sock *sk, u32 skip_to_seq)
+static struct sk_buff *tcp_sacktag_skip(struct sk_buff *skb, struct sock *sk,
+ u32 skip_to_seq)
{
- struct sk_buff *skb;
+ tcp_for_write_queue_from(skb, sk) {
+ if (skb == tcp_send_head(sk))
+ break;
- skb = tcp_write_queue_find(sk, skip_to_seq, 0);
- if (skb == tcp_write_queue_head(sk))
- skb = NULL;
+ if (!before(TCP_SKB_CB(skb)->end_seq, skip_to_seq))
+ break;
+ }
return skb;
}
-static int tcp_handle_dsack(struct sock *sk, struct sk_buff *ack_skb,
- struct tcp_sack_block_wire *sp, u32 *reord,
- int num_sacks, u32 prior_snd_una)
+static struct sk_buff *tcp_maybe_skipping_dsack(struct sk_buff *skb,
+ struct sock *sk,
+ struct tcp_sack_block *next_dup,
+ u32 skip_to_seq,
+ int *fack_count, int *reord,
+ int *flag)
{
- struct tcp_sock *tp = tcp_sk(sk);
- struct sk_buff *skb;
- u32 start_seq_0 = ntohl(get_unaligned(&sp[0].start_seq));
- u32 end_seq_0 = ntohl(get_unaligned(&sp[0].end_seq));
- int flag = 0;
+ if (next_dup == NULL)
+ return skb;
- if (before(start_seq_0, TCP_SKB_CB(ack_skb)->ack_seq)) {
- flag |= FLAG_DSACKING_ACK;
- tcp_dsack_seen(tp);
- NET_INC_STATS_BH(LINUX_MIB_TCPDSACKRECV);
-
- if (!tcp_is_past_dsack_useful(tp, start_seq_0, end_seq_0)) {
- if (!tp->undo_marker)
- NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDNOUNDO);
- else
- NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDOLD);
-
- return flag;
- }
-
- /* D-SACK for already forgotten data... Do dumb counting. */
- if (!after(end_seq_0, prior_snd_una))
- tp->undo_retrans--;
-
- } else if (num_sacks > 1) {
- u32 end_seq_1 = ntohl(get_unaligned(&sp[1].end_seq));
- u32 start_seq_1 = ntohl(get_unaligned(&sp[1].start_seq));
-
- if (!after(end_seq_0, end_seq_1) &&
- !before(start_seq_0, start_seq_1)) {
- flag |= FLAG_DSACKING_ACK;
- tcp_dsack_seen(tp);
- NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFORECV);
- if (!tcp_is_sackblock_valid(tp, start_seq_0, end_seq_0)) {
- /* FIXME, reordering check like in the other place! */
- NET_INC_STATS_BH(LINUX_MIB_TCPSACKDISCARD);
- return flag;
- }
- }
+ if (before(next_dup->start_seq, skip_to_seq)) {
+ skb = tcp_sacktag_skip(skb, sk, next_dup->start_seq);
+ tcp_sacktag_walk(skb, sk, NULL,
+ next_dup->start_seq, next_dup->end_seq,
+ 1, fack_count, reord, flag);
}
- if ((flag & FLAG_DSACKING_ACK) && after(end_seq_0, prior_snd_una)) {
- skb = tcp_write_queue_find(sk, start_seq_0, TCP_WQ_SACKED);
- if (skb != NULL)
- tcp_sacktag_walk(skb, sk, start_seq_0, end_seq_0, 1, reord, &flag, TCP_WQ_SACKED);
-
- skb = tcp_write_queue_find(sk, start_seq_0, 0);
- if (skb != NULL)
- tcp_sacktag_walk(skb, sk, start_seq_0, end_seq_0, 1, reord, &flag, 0);
- }
-
- return flag;
+ return skb;
}
static int tcp_sack_cache_ok(struct tcp_sock *tp, struct tcp_sack_block *cache)
@@ -1431,7 +1420,10 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
int used_sacks;
int reord = tp->packets_out;
int flag = 0;
+ int found_dup_sack = 0;
+ int fack_count;
int i, j;
+ int first_sack_index;
if (!tp->sacked_out) {
if (WARN_ON(tp->fackets_out))
@@ -1439,7 +1431,10 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
tcp_highest_sack_reset(sk);
}
- flag |= tcp_handle_dsack(sk, ack_skb, sp_wire, &reord, num_sacks, prior_snd_una);
+ found_dup_sack = tcp_check_dsack(tp, ack_skb, sp_wire,
+ num_sacks, prior_snd_una);
+ if (found_dup_sack)
+ flag |= FLAG_DSACKING_ACK;
/* Eliminate too old ACKs, but take into
* account more or less fresh ones, they can
@@ -1452,17 +1447,30 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
goto out;
used_sacks = 0;
- for (i = (flag & FLAG_DSACKING_ACK) ? 1 : 0; i < num_sacks; i++) {
+ first_sack_index = 0;
+ for (i = 0; i < num_sacks; i++) {
+ int dup_sack = !i && found_dup_sack;
+
sp[used_sacks].start_seq = ntohl(get_unaligned(&sp_wire[i].start_seq));
sp[used_sacks].end_seq = ntohl(get_unaligned(&sp_wire[i].end_seq));
- if (!tcp_is_sackblock_valid(tp, sp[used_sacks].start_seq,
+ if (!tcp_is_sackblock_valid(tp, dup_sack,
+ sp[used_sacks].start_seq,
sp[used_sacks].end_seq)) {
- /* Don't count olds caused by ACK reordering */
- if ((TCP_SKB_CB(ack_skb)->ack_seq != tp->snd_una) &&
- !after(sp[used_sacks].end_seq, tp->snd_una))
- continue;
- NET_INC_STATS_BH(LINUX_MIB_TCPSACKDISCARD);
+ if (dup_sack) {
+ if (!tp->undo_marker)
+ NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDNOUNDO);
+ else
+ NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDOLD);
+ } else {
+ /* Don't count olds caused by ACK reordering */
+ if ((TCP_SKB_CB(ack_skb)->ack_seq != tp->snd_una) &&
+ !after(sp[used_sacks].end_seq, tp->snd_una))
+ continue;
+ NET_INC_STATS_BH(LINUX_MIB_TCPSACKDISCARD);
+ }
+ if (i == 0)
+ first_sack_index = -1;
continue;
}
@@ -1482,11 +1490,16 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
tmp = sp[j];
sp[j] = sp[j+1];
sp[j+1] = tmp;
+
+ /* Track where the first SACK block goes to */
+ if (j == first_sack_index)
+ first_sack_index = j+1;
}
}
}
skb = tcp_write_queue_head(sk);
+ fack_count = 0;
i = 0;
if (!tp->sacked_out) {
@@ -1503,6 +1516,11 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
while (i < used_sacks) {
u32 start_seq = sp[i].start_seq;
u32 end_seq = sp[i].end_seq;
+ int dup_sack = (found_dup_sack && (i == first_sack_index));
+ struct tcp_sack_block *next_dup = NULL;
+
+ if (found_dup_sack && ((i + 1) == first_sack_index))
+ next_dup = &sp[i + 1];
/* Event "B" in the comment above. */
if (after(end_seq, tp->high_seq))
@@ -1514,36 +1532,36 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
cache++;
/* Can skip some work by looking recv_sack_cache? */
- if (tcp_sack_cache_ok(tp, cache) &&
+ if (tcp_sack_cache_ok(tp, cache) && !dup_sack &&
after(end_seq, cache->start_seq)) {
/* Head todo? */
if (before(start_seq, cache->start_seq)) {
- skb = tcp_sacktag_skip(sk, start_seq);
- if (skb == NULL)
- break;
- skb = tcp_sacktag_walk(skb, sk, start_seq,
- cache->start_seq, 0,
- &reord, &flag, 0);
+ skb = tcp_sacktag_skip(skb, sk, start_seq);
+ skb = tcp_sacktag_walk(skb, sk, next_dup, start_seq,
+ cache->start_seq, dup_sack,
+ &fack_count, &reord, &flag);
}
/* Rest of the block already fully processed? */
if (!after(end_seq, cache->end_seq))
goto advance_sp;
+ skb = tcp_maybe_skipping_dsack(skb, sk, next_dup, cache->end_seq,
+ &fack_count, &reord, &flag);
+
/* ...tail remains todo... */
if (tcp_highest_sack_seq(tp) == cache->end_seq) {
/* ...but better entrypoint exists! */
skb = tcp_highest_sack(sk);
if (skb == NULL)
break;
+ fack_count = tp->fackets_out;
cache++;
goto walk;
}
- skb = tcp_sacktag_skip(sk, cache->end_seq);
- if (skb == NULL)
- break;
+ skb = tcp_sacktag_skip(skb, sk, cache->end_seq);
/* Check overlap against next cached too (past this one already) */
cache++;
continue;
@@ -1553,14 +1571,13 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
skb = tcp_highest_sack(sk);
if (skb == NULL)
break;
+ fack_count = tp->fackets_out;
}
- skb = tcp_sacktag_skip(sk, start_seq);
- if (skb == NULL)
- break;
+ skb = tcp_sacktag_skip(skb, sk, start_seq);
walk:
- skb = tcp_sacktag_walk(skb, sk, start_seq, end_seq,
- 0, &reord, &flag, 0);
+ skb = tcp_sacktag_walk(skb, sk, next_dup, start_seq, end_seq,
+ dup_sack, &fack_count, &reord, &flag);
advance_sp:
/* SACK enhanced FRTO (RFC4138, Appendix B): Clearing correct
@@ -1657,7 +1674,6 @@ int tcp_use_frto(struct sock *sk)
{
const struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
- struct sk_buff *notsacked; /* Or S|R => deny basic F-RTO */
if (!sysctl_tcp_frto)
return 0;
@@ -1669,19 +1685,15 @@ int tcp_use_frto(struct sock *sk)
if (tp->retrans_out > 1)
return 0;
- notsacked = tcp_write_queue_head(sk);
- /* Not interested in head skb here because F-RTO is reentrable if only
- * head skb has been retransmitted (equals to multiple RTOs case)
- */
- notsacked = tcp_write_queue_next(sk, notsacked);
- if ((notsacked != NULL) && TCP_SKB_CB(notsacked)->sacked & TCPCB_RETRANS)
- return 0;
-
- tcp_for_write_queue(skb, sk, TCP_WQ_SACKED) {
+ skb = tcp_write_queue_head(sk);
+ skb = tcp_write_queue_next(sk, skb); /* Skips head */
+ tcp_for_write_queue_from(skb, sk) {
+ if (skb == tcp_send_head(sk))
+ break;
if (TCP_SKB_CB(skb)->sacked&TCPCB_RETRANS)
return 0;
- /* Short-circuit when past first non-SACKed skb */
- if (after(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(notsacked)->seq))
+ /* Short-circuit when first non-SACKed skb has been checked */
+ if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED))
break;
}
return 1;
@@ -1782,7 +1794,7 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag)
if (tcp_is_reno(tp))
tcp_reset_reno_sack(tp);
- tcp_for_write_queue(skb, sk, 0) {
+ tcp_for_write_queue(skb, sk) {
if (skb == tcp_send_head(sk))
break;
@@ -1880,16 +1892,9 @@ void tcp_enter_loss(struct sock *sk, int how)
tp->sacked_out = 0;
tp->fackets_out = 0;
tcp_clear_all_retrans_hints(tp);
-
- tcp_for_write_queue(skb, sk, TCP_WQ_SACKED) {
- /* FIXME, this could be optimized by avoiding tree
- * deletes
- */
- tcp_write_queue_requeue(skb, sk, 0);
- }
}
- tcp_for_write_queue(skb, sk, 0) {
+ tcp_for_write_queue(skb, sk) {
if (skb == tcp_send_head(sk))
break;
@@ -1923,7 +1928,7 @@ static int tcp_check_sack_reneging(struct sock *sk)
* receiver _host_ is heavily congested (or buggy).
* Do processing similar to RTO timeout.
*/
- if ((skb = tcp_real_queue_head(sk)) != NULL &&
+ if ((skb = tcp_write_queue_head(sk)) != NULL &&
(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) {
struct inet_connection_sock *icsk = inet_csk(sk);
NET_INC_STATS_BH(LINUX_MIB_TCPSACKRENEGING);
@@ -2122,21 +2127,6 @@ static void tcp_verify_retransmit_hint(struct tcp_sock *tp,
tp->retransmit_skb_hint = NULL;
}
-/* Simple NewReno thing: Mark head LOST if it wasn't yet and it's below
- * high_seq, stop. That's all.
- */
-static void tcp_mark_head_lost_single(struct sock *sk)
-{
- struct tcp_sock *tp = tcp_sk(sk);
- struct sk_buff *skb = tcp_write_queue_head(sk);
-
- if (!(TCP_SKB_CB(skb)->sacked & TCPCB_LOST) &&
- before(tp->snd_una, tp->high_seq)) {
- TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
- tp->lost_out += tcp_skb_pcount(skb);
- }
-}
-
/* Mark head of queue up as lost. With RFC3517 SACK, the packets is
* is against sacked "cnt", otherwise it's against facked "cnt"
*/
@@ -2145,10 +2135,6 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int fast_rexmit)
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
int cnt;
- unsigned int fc;
- unsigned int fack_count_base;
-
- fack_count_base = TCP_SKB_CB(tcp_write_queue_head(sk))->fack_count;
BUG_TRAP(packets <= tp->packets_out);
if (tp->lost_skb_hint) {
@@ -2159,7 +2145,7 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int fast_rexmit)
cnt = 0;
}
- tcp_for_write_queue_from(skb, sk, 0) {
+ tcp_for_write_queue_from(skb, sk) {
if (skb == tcp_send_head(sk))
break;
/* TODO: do this better */
@@ -2167,18 +2153,9 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int fast_rexmit)
tp->lost_skb_hint = skb;
tp->lost_cnt_hint = cnt;
- fc = TCP_SKB_CB(skb)->fack_count;
- if (tcp_is_fack(tp)) {
- cnt = fc - fack_count_base + tcp_skb_pcount(skb);
- } else {
- if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)
- cnt += tcp_skb_pcount(skb);
- /* Add SACK blocks between this and skb->prev */
- if ((skb != tcp_write_queue_head(sk)) &&
- !tcp_skb_adjacent(sk, skb->prev, skb))
- cnt += fc - TCP_SKB_CB(skb->prev)->fack_count -
- tcp_skb_pcount(skb->prev);
- }
+ if (tcp_is_fack(tp) ||
+ (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))
+ cnt += tcp_skb_pcount(skb);
if (((!fast_rexmit || (tp->lost_out > 0)) && (cnt > packets)) ||
after(TCP_SKB_CB(skb)->end_seq, tp->high_seq))
@@ -2189,6 +2166,7 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int fast_rexmit)
tcp_verify_retransmit_hint(tp, skb);
}
}
+ tcp_verify_left_out(tp);
}
/* Account newly detected lost packet(s) */
@@ -2198,7 +2176,7 @@ static void tcp_update_scoreboard(struct sock *sk, int fast_rexmit)
struct tcp_sock *tp = tcp_sk(sk);
if (tcp_is_reno(tp)) {
- tcp_mark_head_lost_single(sk);
+ tcp_mark_head_lost(sk, 1, fast_rexmit);
} else if (tcp_is_fack(tp)) {
int lost = tp->fackets_out - tp->reordering;
if (lost <= 0)
@@ -2211,8 +2189,6 @@ static void tcp_update_scoreboard(struct sock *sk, int fast_rexmit)
tcp_mark_head_lost(sk, sacked_upto, fast_rexmit);
}
- tcp_verify_left_out(tp);
-
/* New heuristics: it is possible only after we switched
* to restart timer each time when something is ACKed.
* Hence, we can detect timed out packets during fast
@@ -2224,7 +2200,7 @@ static void tcp_update_scoreboard(struct sock *sk, int fast_rexmit)
skb = tp->scoreboard_skb_hint ? tp->scoreboard_skb_hint
: tcp_write_queue_head(sk);
- tcp_for_write_queue_from(skb, sk, 0) {
+ tcp_for_write_queue_from(skb, sk) {
if (skb == tcp_send_head(sk))
break;
if (!tcp_skb_timedout(sk, skb))
@@ -2422,7 +2398,7 @@ static int tcp_try_undo_loss(struct sock *sk)
if (tcp_may_undo(tp)) {
struct sk_buff *skb;
- tcp_for_write_queue(skb, sk, 0) {
+ tcp_for_write_queue(skb, sk) {
if (skb == tcp_send_head(sk))
break;
TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
@@ -2528,8 +2504,11 @@ tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag)
(tcp_fackets_out(tp) > tp->reordering));
int fast_rexmit = 0;
- if (WARN_ON(!tp->packets_out && tp->sacked_out))
+ /* Some technical things:
+ * 1. Reno does not count dupacks (sacked_out) automatically. */
+ if (!tp->packets_out)
tp->sacked_out = 0;
+
if (WARN_ON(!tp->sacked_out && tp->fackets_out))
tp->fackets_out = 0;
@@ -2794,7 +2773,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, s32 *seq_rtt_p,
s32 seq_rtt = -1;
ktime_t last_ackt = net_invalid_timestamp();
- while ((skb = tcp_real_queue_head(sk)) && skb != tcp_send_head(sk)) {
+ while ((skb = tcp_write_queue_head(sk)) && skb != tcp_send_head(sk)) {
struct tcp_skb_cb *scb = TCP_SKB_CB(skb);
u32 end_seq;
u32 acked_pcount;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 5a27e42..652c323 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1849,7 +1849,6 @@ static int tcp_v4_init_sock(struct sock *sk)
struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
- tcp_write_queue_init(sk);
skb_queue_head_init(&tp->out_of_order_queue);
tcp_init_xmit_timers(sk);
tcp_prequeue_init(tp);
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index e1a0e4a..b61b768 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -426,7 +426,6 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
tcp_set_ca_state(newsk, TCP_CA_Open);
tcp_init_xmit_timers(newsk);
- tcp_write_queue_init(newsk);
skb_queue_head_init(&newtp->out_of_order_queue);
newtp->write_seq = treq->snt_isn + 1;
newtp->pushed_seq = newtp->write_seq;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 6110459..9a985b5 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1207,7 +1207,7 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len,
/* Link BUFF into the send queue. */
skb_header_release(buff);
- __tcp_insert_write_queue_after(skb, buff, sk, 0);
+ tcp_insert_write_queue_after(skb, buff, sk);
return 0;
}
@@ -1344,10 +1344,10 @@ static int tcp_mtu_probe(struct sock *sk)
nskb->csum = 0;
nskb->ip_summed = skb->ip_summed;
- __tcp_insert_write_queue_before(nskb, skb, sk);
+ tcp_insert_write_queue_before(nskb, skb, sk);
len = 0;
- tcp_for_write_queue_from_safe(skb, next, sk, 0) {
+ tcp_for_write_queue_from_safe(skb, next, sk) {
copy = min_t(int, skb->len, probe_size - len);
if (nskb->ip_summed)
skb_copy_bits(skb, 0, skb_put(nskb, copy), copy);
@@ -1760,7 +1760,7 @@ void tcp_simple_retransmit(struct sock *sk)
unsigned int mss = tcp_current_mss(sk, 0);
int lost = 0;
- tcp_for_write_queue(skb, sk, 0) {
+ tcp_for_write_queue(skb, sk) {
if (skb == tcp_send_head(sk))
break;
if (skb->len > mss &&
@@ -1848,7 +1848,6 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
(skb->len < (cur_mss >> 1)) &&
(tcp_write_queue_next(sk, skb) != tcp_send_head(sk)) &&
(!tcp_skb_is_last(sk, skb)) &&
- (tcp_skb_adjacent(sk, skb, tcp_write_queue_next(sk, skb))) &&
(skb_shinfo(skb)->nr_frags == 0 && skb_shinfo(tcp_write_queue_next(sk, skb))->nr_frags == 0) &&
(tcp_skb_pcount(skb) == 1 && tcp_skb_pcount(tcp_write_queue_next(sk, skb)) == 1) &&
(sysctl_tcp_retrans_collapse != 0))
@@ -1937,7 +1936,7 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
/* First pass: retransmit lost packets. */
if (tp->lost_out) {
- tcp_for_write_queue_from(skb, sk, 0) {
+ tcp_for_write_queue_from(skb, sk) {
__u8 sacked = TCP_SKB_CB(skb)->sacked;
if (skb == tcp_send_head(sk))
@@ -2010,7 +2009,7 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
else
skb = tcp_write_queue_head(sk);
- tcp_for_write_queue_from(skb, sk, 0) {
+ tcp_for_write_queue_from(skb, sk) {
if (skb == tcp_send_head(sk))
break;
tp->forward_skb_hint = skb;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index d576833..0ef9986 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1886,7 +1886,6 @@ static int tcp_v6_init_sock(struct sock *sk)
struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
- tcp_write_queue_init(sk);
skb_queue_head_init(&tp->out_of_order_queue);
tcp_init_xmit_timers(sk);
tcp_prequeue_init(tp);
--
1.5.0.6
[-- Attachment #2: Type: TEXT/PLAIN, Size: 1866 bytes --]
e595ce2f95a4f6e756cd5e8f6fc896fb2e61da25 Revert recent TCP work
606c0d0a93d76515f097605154a5b374fea6302b [TCP]: Include __tcp_reset_fack_counts to non-__ version
c544afb0997140b65fa9bf77abb6949f2f1ce61d [TCP]: Push fack_count calculation deeper into functions
c89628097889ebc7c8eac710004f15a69484ebed [TCP]: fack_counts more fixes (the previous ones were incomplete)
6c9d05bdcda4fe3fbbe1053b39e0c969781f7196 [PATCH] [TCP]: Fix fack_count miscountings (multiple places)
811560b034530f7ef6b80cde6c0971517ba9e920 [TCP]: Bind fackets_out state to highest_sack more tightly
82207f6525a60c6c48b00c63532efe183754a011 [TCP]: Make invariant check complain about invalid sacked_out
5026c22996f3637fce22f1c7ebbde3c3baeffec1 [TCP]: Create tcp_mark_head_lost_single for NewReno
d7b9a6449bc0e05b5a80ac0948bf721ce1479c4f [TCP]: Fix copy-paste error in tcp_reset_fack_counts
3df630b6213349154da32b0b15ec81d398585413 [TCP]: Fix crash in tcp_advance_send_head
d72d4c2bfbe90759947dae3f8e0169e5dcd76b0a [TCP]: Split write queue into two parts (SACKed and not)
6a3506ce642273af2057953101442d65b1f0fd60 [TCP]: Introduce tcp_skb_adjacent to detect holes in wq
4ca5bc486815ce15915a95f628959e1d21f2528a [TCP]: Introduce tcp_real_queue_head(sk)
0010e0452ffe2c77215672606c6e1467dd81039e [TCP]: Move tcp_advance_highest_sack call early enough
8511d7f270010b41a4349c7629089626068e644d [TCP]: Move tcp_write_queue_empty
99b12c1530796e95383099ae49e1972a5e42f10b [TCP]: Move tcp_check_dsack
1f338928c67e281b295d566ad4ec37dbd1b2524f [TCP]: Use per skb fack count instead of function argument
d8ce7161ec43dc23d33cc43837945fd923e84db0 [TCP]: Added queue parameter to _for_write_queue helpers
fdcf67f30c85ed0ac2dbc31b833b2c6222c64b9c [TCP]: Store retransmit queue packets in RB tree.
305d7dd5dd9aa5c573ec172bb486188ede94453a [TCP]: Introduce per skb fack_counts to retransmit queue
^ permalink raw reply related
* Re: [PATCH 8/8] gianfar: Magic Packet and suspend/resume support.
From: Jeff Garzik @ 2007-12-14 20:24 UTC (permalink / raw)
To: Scott Wood; +Cc: paulus, linuxppc-dev, netdev
In-Reply-To: <20071212173607.GG5596@loki.buserror.net>
Scott Wood wrote:
> Signed-off-by: Scott Wood <scottwood@freescale.com>
> ---
> Jeff, can you ack this to go through Paul's tree
> (assuming nothing wrong with it)?
>
> drivers/net/gianfar.c | 137 ++++++++++++++++++++++++++++++++++++++++-
> drivers/net/gianfar.h | 13 +++-
> drivers/net/gianfar_ethtool.c | 41 ++++++++++++-
> 3 files changed, 185 insertions(+), 6 deletions(-)
ACK
^ permalink raw reply
* Re: [PATCH] sky2: RX lockup fix
From: Jeff Garzik @ 2007-12-14 20:26 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: Peter Tyser, netdev
In-Reply-To: <20071207152215.0267c407@freepuppy.rosehill>
Stephen Hemminger wrote:
> I'm using a Marvell 88E8062 on a custom PPC64 blade and ran into RX
> lockups while validating the sky2 driver. The receive MAC FIFO would
> become stuck during testing with high traffic. One port of the 88E8062
> would lockup, while the other port remained functional. Re-inserting
> the sky2 module would not fix the problem - only a power cycle would.
>
> I looked over Marvell's most recent sk98lin driver and it looks like
> they had a "workaround" for the Yukon XL that the sky2 doesn't have yet.
> The sk98lin driver disables the RX MAC FIFO flush feature for all
> revisions of the Yukon XL.
>
> According to skgeinit.c of the sk98lin driver, "Flushing must be enabled
> (needed for ASF see dev. #4.29), but the flushing mask should be
> disabled (see dev. #4.115)". Nice. I implemented this same change in
> the sky2 driver and verified that the RX lockup I was seeing was
> resolved.
>
> Signed-off-by: Peter Tyser <ptyser@xes-inc.com>
> Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
>
> ---
> Original patch reformatted to remove line wrap.
applied #upstream-fixes
^ permalink raw reply
* Re: [PATCH] e100: free IRQ to remove warningwhenrebooting
From: Jeff Garzik @ 2007-12-14 20:27 UTC (permalink / raw)
To: Auke Kok; +Cc: netdev, jesse.brandeburg, ianw
In-Reply-To: <20071213003042.1895.34327.stgit@localhost.localdomain>
Auke Kok wrote:
> Adapted from Ian Wienand <ianw@gelato.unsw.edu.au>
>
> Explicitly free the IRQ before removing the device to remove a
> warning "Destroying IRQ without calling free_irq"
>
> Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
> Cc: Ian Wienand <ianw@gelato.unsw.edu.au>
> ---
>
> drivers/net/e100.c | 5 ++++-
> 1 files changed, 4 insertions(+), 1 deletions(-)
applied #upstream-fixes
^ permalink raw reply
* Re: [2.6 patch] drivers/net/sis190.c section fix
From: Jeff Garzik @ 2007-12-14 20:27 UTC (permalink / raw)
To: Adrian Bunk; +Cc: romieu, netdev, linux-kernel
In-Reply-To: <20071211222356.GA14204@stusta.de>
Adrian Bunk wrote:
> This patch fixes the following section mismatch with CONFIG_HOTPLUG=n:
>
> <-- snip -->
>
> ...
> WARNING: vmlinux.o(.init.text.20+0x4cb25): Section mismatch: reference to .exit.text:sis190_mii_remove (between 'sis190_init_one' and 'read_eeprom')
> ...
>
> <-- snip -->
>
> Signed-off-by: Adrian Bunk <bunk@kernel.org>
>
> ---
> 29fae057ba15a552a7cad1e731d3238d567032ba
> diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
> index 7200883..49f767b 100644
> --- a/drivers/net/sis190.c
> +++ b/drivers/net/sis190.c
> @@ -1381,7 +1381,7 @@ out:
> return rc;
> }
>
> -static void __devexit sis190_mii_remove(struct net_device *dev)
> +static void sis190_mii_remove(struct net_device *dev)
> {
> struct sis190_private *tp = netdev_priv(dev);
>
>
applied #upstream-fixes
^ permalink raw reply
* Re: [2.6 patch] drivers/net/s2io.c section fixes
From: Jeff Garzik @ 2007-12-14 20:28 UTC (permalink / raw)
To: Adrian Bunk
Cc: ram.vepa, santosh.rastapur, sivakumar.subramani,
sreenivasa.honnur, netdev, linux-kernel
In-Reply-To: <20071211222306.GV14204@stusta.de>
Adrian Bunk wrote:
> Code used by the non-__devinit s2io_open() mustn't be __devinit.
>
> This patch fixes the following section mismatch with CONFIG_HOTPLUG=n:
>
> <-- snip -->
>
> ...
> WARNING: vmlinux.o(.text+0x6f6e3e): Section mismatch: reference to .init.text.20:s2io_test_intr (between 's2io_open' and 's2io_ethtool_sset')
> ...
>
> <-- snip -->
>
> Signed-off-by: Adrian Bunk <bunk@kernel.org>
>
> ---
>
> drivers/net/s2io.c | 4 ++--
applied #upstream-fixes
^ permalink raw reply
* RE: [patch 02/10] forcedeth: power down phy when interface is down
From: Ayaz Abdulla @ 2007-12-14 20:30 UTC (permalink / raw)
To: Andrew Morton, Ed Swierk; +Cc: jeff, netdev
In-Reply-To: <20071213170721.e71ff79f.akpm@linux-foundation.org>
Ed,
You mention that the phy will become 100Mbit half duplex, but during
nv_close, the phy setting is not modified. This might be a separate
issue.
Ayaz
-----Original Message-----
From: Andrew Morton [mailto:akpm@linux-foundation.org]
Sent: Thursday, December 13, 2007 5:07 PM
To: Ed Swierk
Cc: Ayaz Abdulla; jeff@garzik.org; netdev@vger.kernel.org
Subject: Re: [patch 02/10] forcedeth: power down phy when interface is
down
On Thu, 13 Dec 2007 16:53:58 -0800
"Ed Swierk" <eswierk@arastra.com> wrote:
> On 12/13/07, Andrew Morton <akpm@linux-foundation.org> wrote:
> > Does this patch actually fix any observeable problem?
>
> Without the patch, ifconfig down leaves the physical link up, which
> confuses datacenter users who expect the link lights both on the NIC
> and the switch to go out when they bring an interface down.
>
> Furthermore, even though the phy is powered on, autonegotiation stops
> working, so a normally gigabit link might suddenly become 100 Mbit
> half-duplex when the interface goes down, and become gigabit when it
> comes up again.
>
OK, thanks, I added that text to the changelog along with Ayaz's
objection
and shall continue to bug people with it until we have a fix merged.
-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may contain
confidential information. Any unauthorized review, use, disclosure or distribution
is prohibited. If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------
^ permalink raw reply
* Re: [patch 01/10] e1000e: make E1000E default to the same kconfig setting as E1000
From: Jeff Garzik @ 2007-12-14 20:39 UTC (permalink / raw)
To: akpm; +Cc: netdev, randy.dunlap, auke-jan.h.kok, Linux Kernel Mailing List
In-Reply-To: <200712140002.lBE02pUb025505@imap1.linux-foundation.org>
akpm@linux-foundation.org wrote:
> From: Randy Dunlap <randy.dunlap@oracle.com>
>
> Make E1000E default to the same kconfig setting as E1000. So people's
> machiens don't stop working when they use oldconfig.
>
> Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
> Cc: Jeff Garzik <jeff@garzik.org>
> Cc: Auke Kok <auke-jan.h.kok@intel.com>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
> ---
>
> drivers/net/Kconfig | 1 +
> 1 file changed, 1 insertion(+)
>
> diff -puN drivers/net/Kconfig~e1000e-make-e1000e-default-to-the-same-kconfig-setting-as-e1000 drivers/net/Kconfig
> --- a/drivers/net/Kconfig~e1000e-make-e1000e-default-to-the-same-kconfig-setting-as-e1000
> +++ a/drivers/net/Kconfig
> @@ -1986,6 +1986,7 @@ config E1000_DISABLE_PACKET_SPLIT
> config E1000E
> tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
> depends on PCI
> + default E1000
I am not inclined to apply this one. This practice, applied over time,
will tend to accumulate weird 'default' and 'select' statements.
So I think the breakage that occurs is mitigated by two factors:
1) kernel hackers that do their own configs are expected to be able to
figure this stuff.
2) kernel builders (read: distros, mainly) are expected to have put
thought into the Kconfig selection and driver migration strategies.
PCI IDs move across drivers from time, and we don't want to apply these
sorts changes: Viewed in the long term, the suggested patch is merely a
temporary change to allow kernel experts to more easily deal with the
PCI ID migration across drivers.
I would prefer simply to communicate to kernel experts and builders
about a Kconfig issue that could potentially their booting/networking...
because this patch is only needed if the kernel experts do not already
know about a necessary config update.
Jeff
^ permalink raw reply
* Re: kernel 2.6.23.8: KERNEL: assertion in net/ipv4/tcp_input.c
From: Ilpo Järvinen @ 2007-12-14 20:51 UTC (permalink / raw)
To: Wolfgang Walter; +Cc: Netdev
In-Reply-To: <200712131751.15578.wolfgang.walter@studentenwerk.mhn.de>
On Thu, 13 Dec 2007, Wolfgang Walter wrote:
> it happened again with your patch applied:
>
> WARNING: at net/ipv4/tcp_input.c:1018 tcp_sacktag_write_queue()
>
> Call Trace:
> <IRQ> [<ffffffff80549290>] tcp_sacktag_write_queue+0x7d0/0xa60
> [<ffffffff80283869>] add_partial+0x19/0x60
> [<ffffffff80549ac4>] tcp_ack+0x5a4/0x1d70
> [<ffffffff8054e625>] tcp_rcv_established+0x485/0x7b0
> [<ffffffff80554c3d>] tcp_v4_do_rcv+0xed/0x3e0
> [<ffffffff80556fe7>] tcp_v4_rcv+0x947/0x970
> [<ffffffff80538c6c>] ip_local_deliver+0xac/0x290
> [<ffffffff80538862>] ip_rcv+0x362/0x6c0
> [<ffffffff804fc5d3>] netif_receive_skb+0x323/0x420
> [<ffffffff8042ab40>] tg3_poll+0x630/0xa50
> [<ffffffff804fecba>] net_rx_action+0x8a/0x140
> [<ffffffff8023a269>] __do_softirq+0x69/0xe0
> [<ffffffff8020d47c>] call_softirq+0x1c/0x30
> [<ffffffff8020f315>] do_softirq+0x35/0x90
> [<ffffffff8023a105>] irq_exit+0x55/0x60
> [<ffffffff8020f3f0>] do_IRQ+0x80/0x100
> [<ffffffff8020c7d1>] ret_from_intr+0x0/0xa
> <EOI>
...Yeah, as I suspected, left_out != 0 when sacked_out and lost_out are
zero. I'll try to read the code again to see how that could happen (in
any case this is just annoying at the best, no other harm but the
message is being done). ...If nothing comes up I might ask you to run
with another test patch but it might take week or so until I've enough
time to dig into this fully because I must also come familiar with
something as pre-historic as the 2.6.23 (there are already large number
of related changes since then, both in upcoming 2.6.24 and some in
net-2.6.25)... :-)
> > Any tweaking done to TCP related sysctls?
>
> net/core/somaxconn=2048
> net/ipv4/tcp_syncookies=1
> net/ipv4/tcp_max_syn_backlog=8192
> net/ipv4/tcp_max_tw_buckets=1800000
> net/ipv4/tcp_window_scaling=0
> net/ipv4/tcp_timestamps=0
Thanks, these won't be that significant, though timestamps will exclude
some possibilities :-).
--
i.
^ permalink raw reply
* Re: [NETFILTER] xt_hashlimit : speedups hash_dst()
From: Jarek Poplawski @ 2007-12-14 20:59 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Patrick McHardy, netfilter-devel, netdev
In-Reply-To: <4762646B.30207@cosmosbay.com>
Eric Dumazet wrote, On 12/14/2007 12:09 PM:
...
> + /*
> + * Instead of returning hash % ht->cfg.size (implying a divide)
> + * we return the high 32 bits of the (hash * ht->cfg.size) that will
> + * give results between [0 and cfg.size-1] and same hash distribution,
> + * but using a multiply, less expensive than a divide
> + */
> + return ((u64)hash * ht->cfg.size) >> 32;
Are we sure of the same hash distribution? Probably I miss something,
but: if this 'hash' is well distributed on 32 bits, and ht->cfg.size
is smaller than 32 bits, e.g. 256 (8 bits), then this multiplication
moves to the higher 32 of u64 only max. 8 bits of the most significant
byte, and the other three bytes are never used, while division is
always affected by all four bytes...
Regards,
Jarek P.
^ permalink raw reply
* [PATCH] Re: [patch 03/10] forcedeth: fix MAC address detection on network card (regression in 2.6.23)
From: Jeff Garzik @ 2007-12-14 21:06 UTC (permalink / raw)
To: akpm; +Cc: netdev, michael.pyne, AAbdulla, stable
In-Reply-To: <200712140002.lBE02spv025517@imap1.linux-foundation.org>
[-- Attachment #1: Type: text/plain, Size: 3208 bytes --]
akpm@linux-foundation.org wrote:
> From: Michael Pyne <michael.pyne@kdemail.net>
>
> Partially revert a change to mac address detection introduced to the forcedeth
> driver. The change was intended to correct mac address detection for newer
> nVidia chipsets where the mac address was stored in reverse order. One of
> those chipsets appears to still have the mac address in reverse order (or at
> least, it does on my system).
>
> The change that broke mac address detection for my card was commit
> ef756b3e56c68a4d76d9d7b9a73fa8f4f739180f "forcedeth: mac address correct"
>
> My network card is an nVidia built-in Ethernet card, output from lspci as
> follows (with text and numeric ids):
> $ lspci | grep Ethernet
> 00:07.0 Bridge: nVidia Corporation MCP61 Ethernet (rev a2)
> $ lspci -n | grep 07.0
> 00:07.0 0680: 10de:03ef (rev a2)
>
> The vendor id is, of course, nVidia. The device id corresponds to the
> NVIDIA_NVENET_19 entry.
>
> The included patch fixes the MAC address detection on my system.
> Interestingly, the MAC address appears to be in the range reserved for my
> motherboard manufacturer (Gigabyte) and not nVidia.
>
> Signed-off-by: Michael J. Pyne <michael.pyne@kdemail.net>
> Cc: Jeff Garzik <jeff@garzik.org>
> Cc: Ayaz Abdulla <aabdulla@nvidia.com>
> Cc: <stable@kernel.org>
>
> On Wed, 21 Nov 2007 15:34:52 -0800
> "Ayaz Abdulla" <AAbdulla@nvidia.com> wrote:
>
>> The solution is to get the OEM to update their BIOS (instead of
>> integrating this patch) since the MCP61 specs indicate that the MAC
>> Address should be in correct order from BIOS.
>>
>> By changing the feature DEV_HAS_CORRECT_MACADDR to all MCP61 boards, it
>> could cause it to break on other OEM systems who have implemented it
>> correctly.
>>
>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
> ---
>
> drivers/net/forcedeth.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff -puN drivers/net/forcedeth.c~forcedeth-fix-mac-address-detection-on-network-card-regression-in-2623 drivers/net/forcedeth.c
> --- a/drivers/net/forcedeth.c~forcedeth-fix-mac-address-detection-on-network-card-regression-in-2623
> +++ a/drivers/net/forcedeth.c
> @@ -5551,7 +5551,7 @@ static struct pci_device_id pci_tbl[] =
> },
> { /* MCP61 Ethernet Controller */
> PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19),
> - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
> + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
As discussed in the thread (and Michael did provide dmidecode output
IIRC), one "make everybody happy" solution is to use a technique similar
to that found in drivers/ata/ata_piix.c to match a list of BIOS that
have incorrect mac addresses, and clear the feature bit
DEV_HAS_CORRECT_MACADDR.
I have attached an example patch of this approach -- someone merely
needs to take the patch, fill in the blanks, and test it! :)
Jeff
[-- Attachment #2: patch --]
[-- Type: text/plain, Size: 1940 bytes --]
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index a96583c..f7aab9b 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -147,6 +147,7 @@
#include <linux/init.h>
#include <linux/if_vlan.h>
#include <linux/dma-mapping.h>
+#include <linux/dmi.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -4987,6 +4988,26 @@ static int nv_close(struct net_device *dev)
return 0;
}
+static int have_broken_macaddr(void)
+{
+ static const struct dmi_system_id brokenmac_sysids[] = {
+ {
+ .ident = "blahblah",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "MY_VENDOR"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "blahblah"),
+ },
+ },
+
+ { } /* terminate list */
+ };
+
+ if (dmi_check_system(brokenmac_sysids))
+ return 1;
+
+ return 0;
+}
+
static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
{
struct net_device *dev;
@@ -4997,6 +5018,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
u32 powerstate, txreg;
u32 phystate_orig = 0, phystate;
int phyinitialized = 0;
+ int broken_macaddr = 0;
DECLARE_MAC_BUF(mac);
static int printed_version;
@@ -5180,10 +5202,14 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->orig_mac[0] = readl(base + NvRegMacAddrA);
np->orig_mac[1] = readl(base + NvRegMacAddrB);
+ if (!(id->driver_data & DEV_HAS_CORRECT_MACADDR))
+ broken_macaddr = 1;
+ else if (have_broken_macaddr())
+ broken_macaddr = 1;
+
/* check the workaround bit for correct mac address order */
txreg = readl(base + NvRegTransmitPoll);
- if ((txreg & NVREG_TRANSMITPOLL_MAC_ADDR_REV) ||
- (id->driver_data & DEV_HAS_CORRECT_MACADDR)) {
+ if ((txreg & NVREG_TRANSMITPOLL_MAC_ADDR_REV) || (!broken_macaddr)) {
/* mac address is already in correct order */
dev->dev_addr[0] = (np->orig_mac[0] >> 0) & 0xff;
dev->dev_addr[1] = (np->orig_mac[0] >> 8) & 0xff;
^ permalink raw reply related
* Re: [PATCH 00/29] Swap over NFS -v15
From: Daniel Phillips @ 2007-12-14 21:07 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Linus Torvalds, Andrew Morton, linux-kernel, linux-mm, netdev,
trond.myklebust
In-Reply-To: <20071214153907.770251000@chello.nl>
Hi Peter,
A major feature of this patch set is the network receive deadlock
avoidance, but there is quite a bit of stuff bundled with it, the NFS
user accounting for a big part of the patch by itself.
Is it possible to provide a before and after demonstration case for just
the network receive deadlock part, given a subset of the patch set and
a user space recipe that anybody can try?
Regards,
Daniel
^ permalink raw reply
* Re: [PATCH 16/29] netvm: INET reserves.
From: Daniel Phillips @ 2007-12-14 21:10 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Linus Torvalds, Andrew Morton, linux-kernel, linux-mm, netdev,
trond.myklebust
In-Reply-To: <20071214154441.337409000@chello.nl>
Hi Peter,
sysctl_intvec_fragment, proc_dointvec_fragment, sysctl_intvec_fragment
seem to suffer from cut-n-pastitis.
Regards,
Daniel
^ permalink raw reply
* Re: [PATCH 1/2] ixgb: make sure jumbos stay enabled after reset
From: Jeff Garzik @ 2007-12-14 21:13 UTC (permalink / raw)
To: Auke Kok; +Cc: netdev, jesse.brandeburg, matheos.worku
In-Reply-To: <20071214194829.15478.2510.stgit@localhost.localdomain>
Auke Kok wrote:
> From: Matheos Worku <matheos.worku@sun.com>
>
> Currently a device reset (ethtool -r ethX) would cause the
> adapter to fall back to regular MTU sizes.
>
> Signed-off-by: Matheos Worku <matheos.worku@sun.com>
> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
> Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
> ---
>
> drivers/net/ixgb/ixgb_main.c | 16 ++++++++++++++--
> 1 files changed, 14 insertions(+), 2 deletions(-)
applied #upstream-fixes
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox