Netdev List
 help / color / mirror / Atom feed
* [PATCH 1/7] : e1000 Fix possible causing oops of net_rx_action
From: Joonwoo Park @ 2007-12-12  4:01 UTC (permalink / raw)
  To: netdev, linux-kernel; +Cc: 'Kok, Auke', jesse.brandeburg, jgarzik

[NETDEV]: e1000 Fix possible causing oops of net_rx_action
returning work_done == weight as true after calling netif_rx_complete will cause oops in net_rx_action.

Thanks
Joonwoo

Signed-off-by: Joonwoo Park <joonwpark81@gmail.com>
---
 drivers/net/e1000/e1000_main.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 4f37506..4dd61e3 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -3949,6 +3949,8 @@ quit_polling:
 			e1000_set_itr(adapter);
 		netif_rx_complete(poll_dev, napi);
 		e1000_irq_enable(adapter);
+		if (unlikely(work_done == napi->weight))
+			return work_done - 1;
 	}
 
 	return work_done;
---


^ permalink raw reply related

* Re: 2.6.24-rc4-mm1
From: Rik van Riel @ 2007-12-12  4:16 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, netdev
In-Reply-To: <20071204211701.994dfce6.akpm@linux-foundation.org>

On Tue, 4 Dec 2007 21:17:01 -0800
Andrew Morton <akpm@linux-foundation.org> wrote:

> Changes since 2.6.24-rc3-mm2:

2.6.24-rc4-mm1 brought a nice TCP oops on my x86_64 system, while I
was stress-testing the VM and watching via ssh:

general protection fault: 0000 [1] SMP 
last sysfs file: /sys/devices/pci0000:00/0000:00:1c.5/0000:04:00.0/irq
CPU 1 
Modules linked in: nfs lockd nfs_acl rfcomm l2cap bluetooth autofs4 sunrpc ipv6 acpi_cpufreq dm_multipath parport_pc e1000e parport firewire_ohci button i2c_i801 i2c_core i82975x_edac pcspkr firewire_core serio_raw edac_core rtc_cmos floppy crc_itu_t sg sr_mod cdrom pata_marvell ata_piix dm_snapshot dm_zero dm_mirror dm_mod ahci libata sd_mod scsi_mod ext3 jbd mbcache uhci_hcd ohci_hcd ehci_hcd
Pid: 2946, comm: sshd Not tainted 2.6.24-rc4-mm1 #1
RIP: 0010:[<ffffffff81227add>]  [<ffffffff81227add>] __tcp_rb_insert+0x1a/0x67
RSP: 0018:ffff810066401c88  EFLAGS: 00010202
RAX: 6b6b6b6b6b6b6b6b RBX: ffff810076e9f000 RCX: ffff81003ddc9900
RDX: 6b6b6b6b6b6b6bab RSI: ffff81006ed1b148 RDI: 6b6b6b6b6b6b6b5b
RBP: ffff81006ed1aa00 R08: ffff810076e9f010 R09: 00000000bef8d64e
R10: ffffffff81228926 R11: ffffffff8110b2aa R12: ffff810066401de8
R13: 00000000000000e0 R14: ffff810066401ee8 R15: 0000000000000001
FS:  00007f1c2c10d780(0000) GS:ffff81007f801578(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
CR2: 0000000002aabfd3 CR3: 00000000665e3000 CR4: 00000000000006e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process sshd (pid: 2946, threadinfo ffff810066400000, task ffff8100665ce000)
Stack:  ffff81003ddc9900 ffffffff81228b26 0000000000000000 0000000100000000
 ffff810066401ee8 00000000810574da 000004e000000040 000000e0000004e0
 00007f1c2c797620 0000000000000246 0000000066401d60 0000000000000000
Call Trace:
 [<ffffffff81228b26>] tcp_sendmsg+0x21f/0xb00
 [<ffffffff811f0435>] sock_aio_write+0xf8/0x110
 [<ffffffff810a9451>] do_sync_write+0xc9/0x10c
 [<ffffffff811071d3>] file_has_perm+0x9a/0xa9
 [<ffffffff8104e29a>] autoremove_wake_function+0x0/0x2e
 [<ffffffff81059db6>] __lock_acquire+0x50f/0xc8e
 [<ffffffff810574da>] lock_release_holdtime+0x27/0x48
 [<ffffffff810a9c53>] vfs_write+0xd9/0x16f
 [<ffffffff810aa1fd>] sys_write+0x45/0x6e
 [<ffffffff8100c0ba>] tracesys+0xdc/0xe1


Code: 44 3b 4a 1c 79 10 44 3b 4a 18 78 04 0f 0b eb fe 48 8d 50 10 
RIP  [<ffffffff81227add>] __tcp_rb_insert+0x1a/0x67
 RSP <ffff810066401c88>


-- 
"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it." - Brian W. Kernighan

^ permalink raw reply

* Labeled IPsec with NAT
From: Yogesh Raju Sreenivasan @ 2007-12-12  3:37 UTC (permalink / raw)
  To: netdev

[-- Attachment #1: Type: text/plain, Size: 1352 bytes --]


I am working on setting up Labeled IPsec along with iptables nat  
rules. Once I insert nat related rules, the ipsec connection breaks  
and the system tries to re-negotiate and creates multiple SAs. I am  
using 2.6.19 kernel (with Venkat's MLSXFRM patches & bugfixes). I  
guess those were incorporated into the 2.6.20 kernel.

In my case, the function ip_route_me_harder() calls the xfrm_lookup()  
second time which is causing the re-negotiation. I believe it is  
because the flowi->secid field is not set during the second  
xfrm_lookup() call. The ip_route_me_harder() function also calls the  
xfrm_decode_session() which I guess creates/fills the flowi details  
and selinux_xfrm_decode_session fills the flowi->secid from the  
skbuff->sec_path field. But since the skbuff->secpath field is not  
set, the flowi->secid field is reset to 0 on the decode_session()  
call. It seems like we have to fill in the secpath while creating the  
skbuff, before calling the xfrm_decode_session, for the output flow.

Please do let me know if someone has already looked into this issue  
and would be helpful if you could guide me with this. If someone has  
already tested labeled ipsec with NAT and if my understanding is not  
correct do let me know, I am new to linux kernel and finding it  
difficult to reason out the exact cause.

Thanks
Yogesh

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 186 bytes --]

^ permalink raw reply

* Re: Labeled IPsec with NAT
From: Joy Latten @ 2007-12-12  5:03 UTC (permalink / raw)
  To: sreeniva; +Cc: netdev


>I am working on setting up Labeled IPsec along with iptables nat  
>rules. Once I insert nat related rules, the ipsec connection breaks  
>and the system tries to re-negotiate and creates multiple SAs. I am  
>using 2.6.19 kernel (with Venkat's MLSXFRM patches & bugfixes). I  
>guess those were incorporated into the 2.6.20 kernel.

Are you using racoon in ipsec-tools to create labeled SAs?
If so, I recall seeing duplicate SA pairs being created
while using racoon for labeled ipsec. We determined userspace
should manage this.
I posted a patch to ipsec-tools, but I don't think they
ever picked it up... I do not know if this is same problem,
but you could give it a try.

regards,
Joy

^ permalink raw reply

* Re: [Bugme-new] [Bug 9545] New: Cannot bring up a bridge interface without a MAC address set
From: Stephen Hemminger @ 2007-12-12  5:36 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Andrew Morton, netdev, bugme-daemon, berrange, Jeff Garzik,
	Rafael J. Wysocki
In-Reply-To: <20071212015105.GB20618@gondor.apana.org.au>

On Wed, 12 Dec 2007 09:51:05 +0800
Herbert Xu <herbert@gondor.apana.org.au> wrote:

> On Tue, Dec 11, 2007 at 02:52:43PM -0800, Stephen Hemminger wrote:
> >
> > The tap devices have to have addresses don't they. So bringing up an empty
> > bridge is meaningless. If you just add the device first then it will work.
> 
> Actually bringing up a bridge with no constituents is useful for
> a bridge that's made up of only virtual interfaces.  Since each
> vritual interface may be created or destroyed at run-time it'd
> be quite awkward to check every time to see if that's the last
> or first and act differently on the bridge.
> 
> More importantly constiuents can be added to and removed from a
> bridge without taking it down.
> 
> > Could be fixed to prevent errors from existing scripts but it is not a complete showstopper.
> 
> Well this stops FC8 working with Xen so for that it's a showstopper :)
> 
> > The problem is that when device is brought up it propogates events up to
> > other layers and applications, these layers will then query and see a bogus
> > address.
> 
> What exactly would it break for this scenario though?

Well with earlier kernels, ipv6 and others would see an invalid address (all zeros).
That could be a problem if some netlink watching program or udev script
propagated that value into a database or management interface. But now
using a random value, that won't happen.


-- 
Stephen Hemminger <shemminger@linux-foundation.org>

^ permalink raw reply

* Re: [PATCH 6/7] : tehuti Fix possible causing oops of net_rx_action
From: Stephen Hemminger @ 2007-12-12  5:39 UTC (permalink / raw)
  To: Joonwoo Park; +Cc: netdev, linux-kernel, jgarzik, baum, andy
In-Reply-To: <002901c83c73$b089b6e0$9c94fea9@jason>

On Wed, 12 Dec 2007 13:01:27 +0900
"Joonwoo Park" <joonwpark81@gmail.com> wrote:

> [NETDEV]: tehuti Fix possible causing oops of net_rx_action
> 
> Signed-off-by: Joonwoo Park <joonwpark81@gmail.com>
> ---
>  drivers/net/tehuti.c |    2 ++
>  1 files changed, 2 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
> index 21230c9..955e749 100644
> --- a/drivers/net/tehuti.c
> +++ b/drivers/net/tehuti.c
> @@ -305,6 +305,8 @@ static int bdx_poll(struct napi_struct *napi, int budget)
>  
>  		netif_rx_complete(dev, napi);
>  		bdx_enable_interrupts(priv);
> +		if (unlikely(work_done == napi->weight))
> +			return work_done - 1;
>  	}
>  	return work_done;
>  }

A better fix would be not going over budget in the first place.

-- 
Stephen Hemminger <shemminger@linux-foundation.org>

^ permalink raw reply

* [RFC] net: napi fix
From: Stephen Hemminger @ 2007-12-12  5:46 UTC (permalink / raw)
  To: David S. Miller; +Cc: Joonwoo Park, netdev, linux-kernel, jgarzik, baum, andy
In-Reply-To: <20071211213939.122de1db@freepuppy.rosehill>

Isn't this a better fix for all drivers, rather than peppering every
driver with the special case. This is how the logic worked up until
2.6.24.


--- a/net/core/dev.c	2007-12-11 12:16:20.000000000 -0800
+++ b/net/core/dev.c	2007-12-11 21:43:39.000000000 -0800
@@ -2184,7 +2184,7 @@ static void net_rx_action(struct softirq
 
 		have = netpoll_poll_lock(n);
 
-		weight = n->weight;
+		weight = min(n->weight, budget);
 
 		/* This NAPI_STATE_SCHED test is for avoiding a race
 		 * with netpoll's poll_napi().  Only the entity which

^ permalink raw reply

* Re: [PATCH 6/7] : tehuti Fix possible causing oops of net_rx_action
From: Joonwoo Park @ 2007-12-12  5:48 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, linux-kernel, jgarzik, baum, andy
In-Reply-To: <20071211213939.122de1db@freepuppy.rosehill>

2007/12/12, Stephen Hemminger <shemminger@linux-foundation.org>:
> On Wed, 12 Dec 2007 13:01:27 +0900
> "Joonwoo Park" <joonwpark81@gmail.com> wrote:
>
> > [NETDEV]: tehuti Fix possible causing oops of net_rx_action
> >
> > Signed-off-by: Joonwoo Park <joonwpark81@gmail.com>
> > ---
> >  drivers/net/tehuti.c |    2 ++
> >  1 files changed, 2 insertions(+), 0 deletions(-)
> >
> > diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
> > index 21230c9..955e749 100644
> > --- a/drivers/net/tehuti.c
> > +++ b/drivers/net/tehuti.c
> > @@ -305,6 +305,8 @@ static int bdx_poll(struct napi_struct *napi, int budget)
> >
> >               netif_rx_complete(dev, napi);
> >               bdx_enable_interrupts(priv);
> > +             if (unlikely(work_done == napi->weight))
> > +                     return work_done - 1;
> >       }
> >       return work_done;
> >  }
>
> A better fix would be not going over budget in the first place.
>
> --
> Stephen Hemminger <shemminger@linux-foundation.org>
>

Stephen,
This is code of bd_poll().
Do you mean remove napi_stop stuff?

static int bdx_poll(struct napi_struct *napi, int budget)
{
...
        work_done = bdx_rx_receive(priv, &priv->rxd_fifo0, budget);
        if ((work_done < budget) ||
            (priv->napi_stop++ >= 30)) {
                DBG("rx poll is done. backing to isr-driven\n");

                /* from time to time we exit to let NAPI layer release
                 * device lock and allow waiting tasks (eg rmmod) to advance) */
                priv->napi_stop = 0;

                netif_rx_complete(dev, napi);
                bdx_enable_interrupts(priv);
                if (unlikely(work_done == napi->weight))
                        return work_done - 1;
        }
        return work_done;
}

Thanks,
Joonwoo

^ permalink raw reply

* Re: [PATCH 6/7] : tehuti Fix possible causing oops of net_rx_action
From: Stephen Hemminger @ 2007-12-12  5:53 UTC (permalink / raw)
  To: Joonwoo Park; +Cc: netdev, linux-kernel, jgarzik, baum, andy
In-Reply-To: <b25c3fa70712112148u59baea4dl67a6939df4292917@mail.gmail.com>

On Wed, 12 Dec 2007 14:48:27 +0900
"Joonwoo Park" <joonwpark81@gmail.com> wrote:

> 2007/12/12, Stephen Hemminger <shemminger@linux-foundation.org>:
> > On Wed, 12 Dec 2007 13:01:27 +0900
> > "Joonwoo Park" <joonwpark81@gmail.com> wrote:
> >
> > > [NETDEV]: tehuti Fix possible causing oops of net_rx_action
> > >
> > > Signed-off-by: Joonwoo Park <joonwpark81@gmail.com>
> > > ---
> > >  drivers/net/tehuti.c |    2 ++
> > >  1 files changed, 2 insertions(+), 0 deletions(-)
> > >
> > > diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
> > > index 21230c9..955e749 100644
> > > --- a/drivers/net/tehuti.c
> > > +++ b/drivers/net/tehuti.c
> > > @@ -305,6 +305,8 @@ static int bdx_poll(struct napi_struct *napi, int budget)
> > >
> > >               netif_rx_complete(dev, napi);
> > >               bdx_enable_interrupts(priv);
> > > +             if (unlikely(work_done == napi->weight))
> > > +                     return work_done - 1;
> > >       }
> > >       return work_done;
> > >  }
> >
> > A better fix would be not going over budget in the first place.
> >
> > --
> > Stephen Hemminger <shemminger@linux-foundation.org>
> >
> 
> Stephen,
> This is code of bd_poll().
> Do you mean remove napi_stop stuff?
> 
> static int bdx_poll(struct napi_struct *napi, int budget)
> {
> ...
>         work_done = bdx_rx_receive(priv, &priv->rxd_fifo0, budget);
>         if ((work_done < budget) ||
>             (priv->napi_stop++ >= 30)) {

Yes remove the napi_stop stuff, because current NAPI expects device
to be constrained only by budget. If you need to stop sooner, just
set napi weight to be smaller.

>                 DBG("rx poll is done. backing to isr-driven\n");
> 
>                 /* from time to time we exit to let NAPI layer release
>                  * device lock and allow waiting tasks (eg rmmod) to advance) */
>                 priv->napi_stop = 0;
> 
>                 netif_rx_complete(dev, napi);
>                 bdx_enable_interrupts(priv);

With my posted fix to rx_action the following two lines would not be needed.
>                 if (unlikely(work_done == napi->weight))
>                         return work_done - 1;
>         }
>         return work_done;
> }
> 
> Thanks,
> Joonwoo


-- 
Stephen Hemminger <shemminger@linux-foundation.org>

^ permalink raw reply

* Re: [RFC] net: napi fix
From: Joonwoo Park @ 2007-12-12  6:05 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: David S. Miller, netdev, linux-kernel, jgarzik, baum, andy
In-Reply-To: <20071211214634.4dedb274@freepuppy.rosehill>

2007/12/12, Stephen Hemminger <shemminger@linux-foundation.org>:
> Isn't this a better fix for all drivers, rather than peppering every
> driver with the special case. This is how the logic worked up until
> 2.6.24.
>
>
> --- a/net/core/dev.c    2007-12-11 12:16:20.000000000 -0800
> +++ b/net/core/dev.c    2007-12-11 21:43:39.000000000 -0800
> @@ -2184,7 +2184,7 @@ static void net_rx_action(struct softirq
>
>                have = netpoll_poll_lock(n);
>
> -               weight = n->weight;
> +               weight = min(n->weight, budget);
>
>                /* This NAPI_STATE_SCHED test is for avoiding a race
>                 * with netpoll's poll_napi().  Only the entity which
>

Stephen,
Could you explain how it fix the problem?
IMHO I think your patch cannot solve the problem.
The drivers can call netif_rx_complete and net_rx_action can do
list_move_tail also.
Am I missing something?

Thanks
Joonwoo

^ permalink raw reply

* Re: Labeled IPsec with NAT
From: sreeniva @ 2007-12-12  6:10 UTC (permalink / raw)
  To: Joy Latten; +Cc: sreeniva, netdev
In-Reply-To: <200712120503.lBC53AYb028820@faith.austin.ibm.com>

Hi Joy,

>>I am working on setting up Labeled IPsec along with iptables nat
>>rules. Once I insert nat related rules, the ipsec connection breaks
>>and the system tries to re-negotiate and creates multiple SAs. I am
>>using 2.6.19 kernel (with Venkat's MLSXFRM patches & bugfixes). I
>>guess those were incorporated into the 2.6.20 kernel.
>
> Are you using racoon in ipsec-tools to create labeled SAs?
> If so, I recall seeing duplicate SA pairs being created
> while using racoon for labeled ipsec. We determined userspace
> should manage this.
> I posted a patch to ipsec-tools, but I don't think they
> ever picked it up... I do not know if this is same problem,
> but you could give it a try.

Thanks for replying. I am using racoon for testing. I searched for your
patch in the ipsec-tools, but couldn't find it. It would be helpful if you
could point me to the patch.

The reason I was debugging the kernel is because I was under the
assumption that the kernel should not invoke racoon if a matching SA is
available in the SAD (like in my case).

Thanks
Yogesh


^ permalink raw reply

* [PATCH] virtio_net: remove double ether_setup
From: Christian Borntraeger @ 2007-12-12  7:34 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Rusty Russell, virtualization, kvm-devel, netdev
In-Reply-To: <200712121241.48226.rusty@rustcorp.com.au>

Am Mittwoch, 12. Dezember 2007 schrieb Rusty Russell:
> Can you send straight to akpm or davem?  I'm supposed to be on vacation at 

this is a small fix for virtio_net.
virtnet_probe already calls alloc_etherdev, which calls ether_setup.
There is no need to do that again.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
---
 drivers/net/virtio_net.c |    1 -
 1 file changed, 1 deletion(-)

Index: kvm/drivers/net/virtio_net.c
===================================================================
--- kvm.orig/drivers/net/virtio_net.c
+++ kvm/drivers/net/virtio_net.c
@@ -329,11 +329,10 @@ static int virtnet_probe(struct virtio_d
 	dev = alloc_etherdev(sizeof(struct virtnet_info));
 	if (!dev)
 		return -ENOMEM;
 
 	/* Set up network device as normal. */
-	ether_setup(dev);
 	dev->open = virtnet_open;
 	dev->stop = virtnet_close;
 	dev->hard_start_xmit = start_xmit;
 	dev->features = NETIF_F_HIGHDMA;
 	SET_NETDEV_DEV(dev, &vdev->dev);



^ permalink raw reply

* [PATCH] Net: Remove FASTCALL macro
From: Harvey Harrison @ 2007-12-12  8:09 UTC (permalink / raw)
  To: netdev; +Cc: Ingo Molnar, LKML

X86_32 was the last user of the FASTCALL macro, now that it
uses regparm(3) by default, this macro expands to nothing.

Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com>
---
Should this be coordinated with the FASTCALL() removal in the
x86 git tree?

 drivers/net/ns83820.c          |    5 +----
 include/net/bluetooth/rfcomm.h |    4 ++--
 include/net/sock.h             |    4 ++--
 3 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index ea71f6d..972acc3 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -611,7 +611,7 @@ static inline int rx_refill(struct net_device *ndev, gfp_t gfp)
 	return i ? 0 : -ENOMEM;
 }
 
-static void FASTCALL(rx_refill_atomic(struct net_device *ndev));
+static void rx_refill_atomic(struct net_device *ndev));
 static void fastcall rx_refill_atomic(struct net_device *ndev)
 {
 	rx_refill(ndev, GFP_ATOMIC);
@@ -633,7 +633,6 @@ static inline void clear_rx_desc(struct ns83820 *dev, unsigned i)
 	build_rx_desc(dev, dev->rx_info.descs + (DESC_SIZE * i), 0, 0, CMDSTS_OWN, 0);
 }
 
-static void FASTCALL(phy_intr(struct net_device *ndev));
 static void fastcall phy_intr(struct net_device *ndev)
 {
 	struct ns83820 *dev = PRIV(ndev);
@@ -832,7 +831,6 @@ static void ns83820_cleanup_rx(struct ns83820 *dev)
 	}
 }
 
-static void FASTCALL(ns83820_rx_kick(struct net_device *ndev));
 static void fastcall ns83820_rx_kick(struct net_device *ndev)
 {
 	struct ns83820 *dev = PRIV(ndev);
@@ -854,7 +852,6 @@ static void fastcall ns83820_rx_kick(struct net_device *ndev)
 /* rx_irq
  *
  */
-static void FASTCALL(rx_irq(struct net_device *ndev));
 static void fastcall rx_irq(struct net_device *ndev)
 {
 	struct ns83820 *dev = PRIV(ndev);
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
index 25aa575..98ec7a3 100644
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -252,8 +252,8 @@ static inline void rfcomm_dlc_put(struct rfcomm_dlc *d)
 		rfcomm_dlc_free(d);
 }
 
-extern void FASTCALL(__rfcomm_dlc_throttle(struct rfcomm_dlc *d));
-extern void FASTCALL(__rfcomm_dlc_unthrottle(struct rfcomm_dlc *d));
+extern void __rfcomm_dlc_throttle(struct rfcomm_dlc *d);
+extern void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d);
 
 static inline void rfcomm_dlc_throttle(struct rfcomm_dlc *d)
 {
diff --git a/include/net/sock.h b/include/net/sock.h
index 67e35c7..bdad9ba 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -812,14 +812,14 @@ do {									\
 	lockdep_init_map(&(sk)->sk_lock.dep_map, (name), (key), 0);	\
 } while (0)
 
-extern void FASTCALL(lock_sock_nested(struct sock *sk, int subclass));
+extern void lock_sock_nested(struct sock *sk, int subclass);
 
 static inline void lock_sock(struct sock *sk)
 {
 	lock_sock_nested(sk, 0);
 }
 
-extern void FASTCALL(release_sock(struct sock *sk));
+extern void release_sock(struct sock *sk);
 
 /* BH context may only use the following locking interface. */
 #define bh_lock_sock(__sk)	spin_lock(&((__sk)->sk_lock.slock))
-- 
1.5.3.7.2212.gd092




^ permalink raw reply related

* Re: [PATCH 7/7] : myri10ge Fix possible causing oops of net_rx_action
From: Subrata Modak @ 2007-12-12  8:30 UTC (permalink / raw)
  To: Joonwoo Park; +Cc: netdev, linux-kernel, jgarzik, help
In-Reply-To: <002801c83c73$af10f990$9c94fea9@jason>

Would you like to submit the Driver Test Cases to LTP ? Or, if you have
your Driver test cases written in C, we can port to LTP and have it
inside the LTP package.
You can also check out the following links for more info, and can always
ping me for anything:
http://ltp.cvs.sourceforge.net/ltp/ltp/testcases/kernel/device-drivers/,
http://ltp.sourceforge.net/documentation/how-to/ltp.php?

Regards--
Subrata
(LTP Maintainer)

On Wed, 2007-12-12 at 13:01 +0900, Joonwoo Park wrote:
> [NETDEV]: myri10ge Fix possible causing oops of net_rx_action
> 
> Signed-off-by: Joonwoo Park <joonwpark81@gmail.com>
> ---
>  drivers/net/myri10ge/myri10ge.c |    2 ++
>  1 files changed, 2 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
> index 8def865..57311ed 100644
> --- a/drivers/net/myri10ge/myri10ge.c
> +++ b/drivers/net/myri10ge/myri10ge.c
> @@ -1242,6 +1242,8 @@ static int myri10ge_poll(struct napi_struct *napi, int budget)
>  	if (work_done < budget || !netif_running(netdev)) {
>  		netif_rx_complete(netdev, napi);
>  		put_be32(htonl(3), mgp->irq_claim);
> +		if (unlikely(work_done == napi->weight))
> +			return work_done - 1;
>  	}
>  	return work_done;
>  }
> ---
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/


^ permalink raw reply

* [PATCH 1/4] cxgb2: rtnl_lock out of loop will be faster
From: Wang Chen @ 2007-12-12  8:46 UTC (permalink / raw)
  To: David S. Miller, Jeff Garzik; +Cc: maintainers, netdev, Wang Chen

[PATCH 1/4] [NETDEV] cxgb2: rtnl_lock out of loop will be faster

Before this patch, it gets and releases the lock at each
iteration of the loop. Changing unregister_netdev to
unregister_netdevice and locking outside of the loop will
be faster for this approach.

Signed-off-by: Wang Chen <wangchen@cn.fujitsu.com>
---
 cxgb2.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletion(-)

--- linux-2.6.24.rc5.org/drivers/net/chelsio/cxgb2.c	2007-12-12 10:19:39.000000000 +0800
+++ linux-2.6.24.rc5/drivers/net/chelsio/cxgb2.c	2007-12-12 16:24:14.000000000 +0800
@@ -46,6 +46,7 @@
 #include <linux/mii.h>
 #include <linux/sockios.h>
 #include <linux/dma-mapping.h>
+#include <linux/rtnetlink.h>
 #include <asm/uaccess.h>
 
 #include "cpl5_cmd.h"
@@ -1387,10 +1388,12 @@ static void __devexit remove_one(struct 
 	struct adapter *adapter = dev->priv;
 	int i;
 
+	rtnl_lock();
 	for_each_port(adapter, i) {
 		if (test_bit(i, &adapter->registered_device_map))
-			unregister_netdev(adapter->port[i].dev);
+			unregister_netdevice(adapter->port[i].dev);
 	}
+	rtnl_unlock();
 
 	t1_free_sw_modules(adapter);
 	iounmap(adapter->regs);


^ permalink raw reply

* [PATCH 3/4] ixp2000: rtnl_lock out of loop will be faster
From: Wang Chen @ 2007-12-12  8:48 UTC (permalink / raw)
  To: David S. Miller, Jeff Garzik; +Cc: buytenh, netdev, Wang Chen

[PATCH 3/4] [NETDEV] ixp2000: rtnl_lock out of loop will be faster

Before this patch, it gets and releases the lock at each
iteration of the loop. Changing unregister_netdev to
unregister_netdevice and locking outside of the loop will
be faster for this approach.

Signed-off-by: Wang Chen <wangchen@cn.fujitsu.com>
---
 ixpdev.c |   12 +++++++++---
 1 files changed, 9 insertions(+), 3 deletions(-)

diff -Nurp linux-2.6.24.rc5.org/drivers/net/ixp2000/ixpdev.c linux-2.6.24.rc5/drivers/net/ixp2000/ixpdev.c
--- linux-2.6.24.rc5.org/drivers/net/ixp2000/ixpdev.c	2007-12-12 10:19:41.000000000 +0800
+++ linux-2.6.24.rc5/drivers/net/ixp2000/ixpdev.c	2007-12-12 16:25:44.000000000 +0800
@@ -15,6 +15,7 @@
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/moduleparam.h>
+#include <linux/rtnetlink.h>
 #include <asm/hardware/uengine.h>
 #include <asm/mach-types.h>
 #include <asm/io.h>
@@ -375,14 +376,16 @@ int ixpdev_init(int __nds_count, struct 
 	ixp2000_uengine_load(1, &ixp2400_tx);
 	ixp2000_uengine_start_contexts(1, 0xff);
 
+	rtnl_lock();
 	for (i = 0; i < nds_count; i++) {
-		err = register_netdev(nds[i]);
+		err = register_netdevice(nds[i]);
 		if (err) {
 			while (--i >= 0)
-				unregister_netdev(nds[i]);
+				unregister_netdevice(nds[i]);
 			goto err_free_tx;
 		}
 	}
+	rtnl_unlock();
 
 	for (i = 0; i < nds_count; i++) {
 		printk(KERN_INFO "%s: IXP2000 MSF ethernet (port %d), "
@@ -395,6 +398,7 @@ int ixpdev_init(int __nds_count, struct 
 	return 0;
 
 err_free_tx:
+	rtnl_unlock();
 	for (i = 0; i < TX_BUF_COUNT; i++)
 		free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr));
 
@@ -412,8 +416,10 @@ void ixpdev_deinit(void)
 
 	/* @@@ Flush out pending packets.  */
 
+	rtnl_lock();
 	for (i = 0; i < nds_count; i++)
-		unregister_netdev(nds[i]);
+		unregister_netdevice(nds[i]);
+	rtnl_unlock();
 
 	ixp2000_uengine_stop_contexts(1, 0xff);
 	ixp2000_uengine_stop_contexts(0, 0xff);


^ permalink raw reply

* [PATCH 2/4] cxgb3: rtnl_lock out of loop will be faster
From: Wang Chen @ 2007-12-12  8:47 UTC (permalink / raw)
  To: David S. Miller, Jeff Garzik; +Cc: netdev, Wang Chen

[PATCH 2/4] [NETDEV] cxgb3: rtnl_lock out of loop will be faster

Before this patch, it gets and releases the lock at each
iteration of the loop. Changing unregister_netdev to
unregister_netdevice and locking outside of the loop will
be faster for this approach.

Signed-off-by: Wang Chen <wangchen@cn.fujitsu.com>
---
 cxgb3_main.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletion(-)

--- linux-2.6.24.rc5.org/drivers/net/cxgb3/cxgb3_main.c	2007-12-12 10:19:39.000000000 +0800
+++ linux-2.6.24.rc5/drivers/net/cxgb3/cxgb3_main.c	2007-12-12 15:19:15.000000000 +0800
@@ -2584,9 +2584,11 @@ static void __devexit remove_one(struct 
 		sysfs_remove_group(&adapter->port[0]->dev.kobj,
 				   &cxgb3_attr_group);
 
+		rtnl_lock();
 		for_each_port(adapter, i)
 		    if (test_bit(i, &adapter->registered_device_map))
-			unregister_netdev(adapter->port[i]);
+			unregister_netdevice(adapter->port[i]);
+		rtnl_unlock();
 
 		if (is_offload(adapter)) {
 			cxgb3_adapter_unofld(adapter);


^ permalink raw reply

* [PATCH 4/4] sky2: rtnl_lock out of loop will be faster
From: Wang Chen @ 2007-12-12  8:50 UTC (permalink / raw)
  To: David S. Miller, Jeff Garzik; +Cc: shemminger, netdev, Wang Chen

[PATCH 4/4] [NETDEV] sky2: rtnl_lock out of loop will be faster

Before this patch, it gets and releases the lock at each
iteration of the loop. Changing unregister_netdev to
unregister_netdevice and locking outside of the loop will
be faster for this approach.

Signed-off-by: Wang Chen <wangchen@cn.fujitsu.com>
---
 sky2.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletion(-)

--- linux-2.6.24.rc5.org/drivers/net/sky2.c	2007-12-12 10:19:43.000000000 +0800
+++ linux-2.6.24.rc5/drivers/net/sky2.c	2007-12-12 15:23:37.000000000 +0800
@@ -4270,8 +4270,10 @@ static void __devexit sky2_remove(struct
 	del_timer_sync(&hw->watchdog_timer);
 	cancel_work_sync(&hw->restart_work);
 
+	rtnl_lock();
 	for (i = hw->ports-1; i >= 0; --i)
-		unregister_netdev(hw->dev[i]);
+		unregister_netdevice(hw->dev[i]);
+	rtnl_unlock();
 
 	sky2_write32(hw, B0_IMSK, 0);


^ permalink raw reply

* Re: [4/4] DST: Algorithms used in distributed storage.
From: Dmitry Monakhov @ 2007-12-12  9:12 UTC (permalink / raw)
  To: Evgeniy Polyakov; +Cc: lkml, netdev, linux-fsdevel
In-Reply-To: <11972872511718@2ka.mipt.ru>

On 14:47 Mon 10 Dec     , Evgeniy Polyakov wrote:
> 
> Algorithms used in distributed storage.
> Mirror and linear mapping code.
Hi, i've finally take a look on your DST solution.
It seems what your current implementation will not work on nonstandard
devices for example software raid0.
other comments are follows:
> 
> Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
> 
> 
> diff --git a/drivers/block/dst/alg_linear.c b/drivers/block/dst/alg_linear.c
> new file mode 100644
> index 0000000..9dc0976
> --- /dev/null
> +++ b/drivers/block/dst/alg_linear.c
> @@ -0,0 +1,105 @@
> +/*
> + * 2007+ Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
> + * All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/dst.h>
> +
> +static struct dst_alg *alg_linear;
> +
> +/*
> + * This callback is invoked when node is removed from storage.
> + */
> +static void dst_linear_del_node(struct dst_node *n)
> +{
> +}
> +
> +/*
> + * This callback is invoked when node is added to storage.
> + */
> +static int dst_linear_add_node(struct dst_node *n)
> +{
> +	struct dst_storage *st = n->st;
> +
> +	dprintk("%s: disk_size: %llu, node_size: %llu.\n",
> +			__func__, st->disk_size, n->size);
> +
> +	mutex_lock(&st->tree_lock);
> +	n->start = st->disk_size;
> +	st->disk_size += n->size;
> +	set_capacity(st->disk, st->disk_size);
> +	mutex_unlock(&st->tree_lock);
> +
> +	return 0;
> +}
> +
> +static int dst_linear_remap(struct dst_request *req)
> +{
> +	int err;
> +
> +	if (req->node->bdev) {
> +		generic_make_request(req->bio);
> +		return 0;
> +	}
> +
> +	err = kst_check_permissions(req->state, req->bio);
> +	if (err)
> +		return err;
> +
> +	return req->state->ops->push(req);
> +}
> +
> +/*
> + * Failover callback - it is invoked each time error happens during
> + * request processing.
> + */
> +static int dst_linear_error(struct kst_state *st, int err)
> +{
> +	if (err)
> +		set_bit(DST_NODE_FROZEN, &st->node->flags);
> +	else
> +		clear_bit(DST_NODE_FROZEN, &st->node->flags);
> +	return 0;
> +}
> +
> +static struct dst_alg_ops alg_linear_ops = {
> +	.remap		= dst_linear_remap,
> +	.add_node 	= dst_linear_add_node,
> +	.del_node 	= dst_linear_del_node,
> +	.error		= dst_linear_error,
> +	.owner		= THIS_MODULE,
> +};
> +
> +static int __devinit alg_linear_init(void)
> +{
> +	alg_linear = dst_alloc_alg("alg_linear", &alg_linear_ops);
> +	if (!alg_linear)
> +		return -ENOMEM;
> +
> +	return 0;
> +}
> +
> +static void __devexit alg_linear_exit(void)
> +{
> +	dst_remove_alg(alg_linear);
> +}
> +
> +module_init(alg_linear_init);
> +module_exit(alg_linear_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
> +MODULE_DESCRIPTION("Linear distributed algorithm.");
> diff --git a/drivers/block/dst/alg_mirror.c b/drivers/block/dst/alg_mirror.c
> new file mode 100644
> index 0000000..3c457ff
> --- /dev/null
> +++ b/drivers/block/dst/alg_mirror.c
> @@ -0,0 +1,1128 @@
> +/*
> + * 2007+ Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
> + * All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/poll.h>
> +#include <linux/dst.h>
> +
> +struct dst_mirror_node_data
> +{
> +	u64		age;
> +};
> +
> +struct dst_mirror_priv
> +{
> +	unsigned int		chunk_num;
> +
> +	u64			last_start;
> +
> +	spinlock_t		backlog_lock;
> +	struct list_head	backlog_list;
> +
> +	struct dst_mirror_node_data	old_data, new_data;
> +
> +	unsigned long		*chunk;
> +};
> +
> +static struct dst_alg *alg_mirror;
> +static struct bio_set *dst_mirror_bio_set;
> +
> +static int dst_mirror_resync(struct dst_node *n, int ndp);
> +
> +static void dst_mirror_mark_sync(struct dst_node *n)
> +{
> +	if (test_bit(DST_NODE_NOTSYNC, &n->flags)) {
> +		struct dst_mirror_priv *priv = n->priv;
> +
> +		clear_bit(DST_NODE_NOTSYNC, &n->flags);
> +		dprintk("%s: node: %p, %llu:%llu synchronization "
> +				"has been completed.\n",
> +			__func__, n, n->start, n->size);
> +		priv->old_data.age = 0;
> +	}
> +}
> +
> +static void dst_mirror_mark_notsync(struct dst_node *n)
> +{
> +	if (!test_bit(DST_NODE_NOTSYNC, &n->flags)) {
> +		set_bit(DST_NODE_NOTSYNC, &n->flags);
> +		dprintk("%s: not synced node n: %p.\n", __func__, n);
> +	}
> +}
> +
> +static void dst_mirror_mark_node_notsync(struct dst_node *n)
> +{
> +	struct dst_mirror_priv *p = n->priv;
> +
> +	memset(p->chunk, 0xff, DIV_ROUND_UP(p->chunk_num, BITS_PER_LONG)*sizeof(long));
> +	dst_mirror_mark_notsync(n);
> +	dst_mirror_resync(n, 0);
> +}
> +
> +static void dst_mirror_mark_node_sync(struct dst_node *n)
> +{
> +	struct dst_mirror_priv *p = n->priv;
> +
> +	memset(p->chunk, 0x0, DIV_ROUND_UP(p->chunk_num, BITS_PER_LONG)*sizeof(long));
> +	dst_mirror_mark_sync(n);
> +}
> +
> +static ssize_t dst_mirror_mark_dirty(struct device *dev, struct device_attribute *attr,
> +			 const char *buf, size_t count)
> +{
> +	struct dst_node *n = container_of(dev, struct dst_node, device);
> +
> +	dst_mirror_mark_node_notsync(n);
> +	return count;
> +}
> +
> +static ssize_t dst_mirror_mark_clean(struct device *dev, struct device_attribute *attr,
> +			 const char *buf, size_t count)
> +{
> +	struct dst_node *n = container_of(dev, struct dst_node, device);
> +
> +	dst_mirror_mark_node_sync(n);
> +	return count;
> +}
> +
> +static ssize_t dst_mirror_chunk_mask_show(struct device *dev,
> +		struct device_attribute *attr, char *buf)
> +{
> +	struct dst_node *n = container_of(dev, struct dst_node, device);
> +	struct dst_mirror_priv *priv = n->priv;
> +	unsigned int i;
> +	int rest = PAGE_SIZE, rest_bits = priv->chunk_num;
> +
> +	for (i = 0; i < DIV_ROUND_UP(priv->chunk_num, BITS_PER_LONG); ++i) {
> +		int bit, j;
> +
> +		for (j = 0; j < min(BITS_PER_LONG, rest_bits); ++j) {
> +			bit = (priv->chunk[i] >> j) & 1;
> +			sprintf(buf, "%c", (bit)?'+':'-');
> +			buf++;
> +		}
> +
> +		rest_bits -= j;
> +		rest -= j;
> +
> +		if (rest < BITS_PER_LONG || rest_bits <= 0)
> +			break;
> +	}
> +
> +	return PAGE_SIZE - rest;
> +}
> +
> +static struct device_attribute dst_mirror_attrs[] = {
> +	__ATTR(chunks, S_IRUGO, dst_mirror_chunk_mask_show, NULL),
> +	__ATTR(dirty, S_IWUSR, NULL, dst_mirror_mark_dirty),
> +	__ATTR(clean, S_IWUSR, NULL, dst_mirror_mark_clean),
> +};
> +
> +/*
> + * This callback is invoked when node is removed from storage.
> + */
> +static void dst_mirror_del_node(struct dst_node *n)
> +{
> +	struct dst_mirror_priv *priv = n->priv;
> +	struct dst_request *req, *tmp;
> +
> +	list_for_each_entry_safe(req, tmp, &priv->backlog_list, request_list_entry) {
> +		kst_del_req(req);
> +		kst_complete_req(req, -ENODEV);
> +	}
> +
> +	if (priv) {
> +		vfree(priv->chunk);
> +		kfree(priv);
> +		n->priv = NULL;
> +	}
> +
> +	if (n->device.parent == &n->st->device) {
> +		int i;
> +
> +		for (i=0; i<ARRAY_SIZE(dst_mirror_attrs); ++i)
> +			device_remove_file(&n->device, &dst_mirror_attrs[i]);
> +	}
> +}
> +
> +static void dst_mirror_handle_priv(struct dst_node *n)
> +{
> +	if (n->priv) {
> +		int err, i;
> +
> +		for (i=0; i<ARRAY_SIZE(dst_mirror_attrs); ++i)
> +			err = device_create_file(&n->device,
> +					&dst_mirror_attrs[i]);
> +	}
> +}
> +
> +static void dst_mirror_destructor(struct bio *bio)
> +{
> +	dprintk("%s: bio: %p.\n", __func__, bio);
> +	bio_free(bio, dst_mirror_bio_set);
> +}
> +
> +/*
> + * This function copies node's private on-disk data from first node
> + * to the new one.
> + */
> +static int dst_mirror_get_node_data(struct dst_node *n,
> +		struct dst_mirror_node_data *ndata, int old)
> +{
> +	struct dst_node *first;
> +	struct dst_mirror_priv *p;
> +
> +	mutex_lock(&n->st->tree_lock);
> +	first = dst_storage_tree_search(n->st, n->start);
> +	mutex_unlock(&n->st->tree_lock);
> +	if (!first) {
> +		dprintk("%s: there are no nodes in the storage.\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +	p = first->priv;
> +	memcpy(ndata, (old)?&p->old_data:&p->new_data, sizeof(struct dst_mirror_node_data));
> +
> +	dst_node_put(first);
> +	return 0;
> +}
> +
> +struct dst_mirror_ndp
> +{
> +	int			err;
> +	struct page		*page;
> +	struct completion	complete;
> +};
> +
> +static void dst_mirror_ndb_complete(struct dst_mirror_ndp *cmp, int err)
> +{
> +	cmp->err = err;
> +	dprintk("%s: completing request: cmp: %p, err: %d.\n",
> +			__func__, cmp, err);
> +	complete(&cmp->complete);
> +}
> +
> +static void dst_mirror_ndp_bio_endio(struct dst_request *req, int err)
> +{
> +	struct dst_mirror_ndp *cmp = req->bio->bi_private;
> +
> +	dst_mirror_ndb_complete(cmp, err);
> +}
> +
> +static int dst_mirror_ndp_end_io(struct bio *bio, unsigned int size, int err)
> +{
> +	struct dst_mirror_ndp *cmp = bio->bi_private;
> +
> +	if (bio->bi_size)
> +		return 0;
> +
> +	dst_mirror_ndb_complete(cmp, err);
> +	return 0;
> +}
> +
> +/*
> + * This function reads or writes node's private data from underlying media.
> + */
> +static int dst_mirror_process_node_data(struct dst_node *n,
> +		struct dst_mirror_node_data *ndata, int op)
> +{
> +	struct bio *bio;
> +	int err = -ENOMEM;
> +	struct dst_mirror_ndp *cmp;
> +	void *addr;
> +
> +	cmp = kzalloc(sizeof(struct dst_mirror_ndp), GFP_KERNEL);
> +	if (!cmp)
> +		goto err_out_exit;
> +
> +	cmp->page = alloc_page(GFP_NOIO);
> +	if (!cmp->page)
> +		goto err_out_free_cmp;
> +
> +	addr = kmap(cmp->page);
> +
> +	init_completion(&cmp->complete);
> +
> +	if (op == WRITE)
> +		memcpy(addr, ndata, sizeof(struct dst_mirror_node_data));
> +
> +	bio = bio_alloc_bioset(GFP_NOIO, 1, dst_mirror_bio_set);
> +	if (!bio)
> +		goto err_out_free_page;
> +
> +	bio->bi_rw = op;
> +	bio->bi_private = cmp;
> +	bio->bi_sector = n->size;
> +	bio->bi_bdev = n->bdev;
> +	bio->bi_destructor = dst_mirror_destructor;
> +	bio->bi_end_io = dst_mirror_ndp_end_io;
> +
> +	err = bio_add_pc_page(n->st->queue, bio, cmp->page, 512, 0);
> +	if (err <= 0)
> +		goto err_out_free_bio;
> +
> +	if (n->bdev) {
> +		generic_make_request(bio);
> +	} else {
> +		struct dst_request req;
> +
> +		memset(&req, 0, sizeof(struct dst_request));
> +
> +		req.node = n;
> +		req.state = n->state;
> +		req.start = bio->bi_sector;
> +		req.size = req.orig_size = bio->bi_size;
> +		req.bio = bio;
> +		req.idx = bio->bi_idx;
> +		req.num = bio->bi_vcnt;
> +		req.flags = 0;
> +		req.offset = 0;
> +		req.bio_endio = &dst_mirror_ndp_bio_endio;
> +		req.callback = &kst_data_callback;
> +
> +		err = req.state->ops->push(&req);
> +		if (err)
> +			req.bio_endio(&req, err);
> +	}
> +
> +	dprintk("%s: waiting for completion: bio: %p, cmp: %p.\n",
> +			__func__, bio, cmp);
> +
> +	wait_for_completion(&cmp->complete);
> +
> +	err = cmp->err;
> +
> +	if (!err && (op != WRITE))
> +		memcpy(ndata, addr, sizeof(struct dst_mirror_node_data));
> +
> +	kunmap(cmp->page);
<< MINOR_BUG:
   You has forgot to unmap page on error path, so IMHO it is better to move
   kunmap to "err_out_free_cmp" label.
> +
> +	dprintk("%s: freeing bio: %p, err: %d.\n", __func__, bio, err);
> +
> +err_out_free_bio:
> +	bio_put(bio);
> +err_out_free_page:
> +	__free_page(cmp->page);
> +err_out_free_cmp:
> +	kfree(cmp);
> +err_out_exit:
> +	return err;
> +}
> +
> +/*
> + * This function reads node's private data from underlying media.
> + */
> +static int dst_mirror_read_node_data(struct dst_node *n,
> +		struct dst_mirror_node_data *ndata)
> +{
> +	return dst_mirror_process_node_data(n, ndata, READ);
> +}
> +
> +/*
> + * This function writes node's private data from underlying media.
> + */
> +static int dst_mirror_write_node_data(struct dst_node *n,
> +		struct dst_mirror_node_data *ndata)
> +{
> +	dprintk("%s: writing new age: %llx, node: %p %llu-%llu.\n",
> +			__func__, ndata->age, n, n->start, n->size);
> +	return dst_mirror_process_node_data(n, ndata, WRITE);
> +}
> +
> +static int dst_mirror_ndp_setup(struct dst_node *n, int first_node, int clean_on_sync)
> +{
> +	struct dst_mirror_priv *p = n->priv;
> +	int sync = 1, err;
> +
> +	err = dst_mirror_read_node_data(n, &p->old_data);
> +	if (err)
> +		return err;
> +
> +	if (first_node) {
> +		p->new_data.age = *(u64 *)&n->st;
> +
> +		dprintk("%s: first age: %llx -> %llx. "
> +			"Old will be set to new for the first node.\n",
> +				__func__, p->old_data.age, p->new_data.age);
> +
> +		err = dst_mirror_write_node_data(n, &p->new_data);
> +		if (err)
> +			return err;
> +		p->old_data.age = p->new_data.age;
> +	} else {
> +		err = dst_mirror_get_node_data(n, &p->new_data, 1);
> +		if (err)
> +			return err;
> +
> +		if (p->new_data.age != p->old_data.age) {
> +			sync = 0;
> +			dprintk("%s: node %llu:%llu is not synced with the first "
> +					"node (old != new): %llx != %llx.\n",
> +					__func__, n->start, n->start+n->size,
> +					p->old_data.age, p->new_data.age);
> +			err = dst_mirror_get_node_data(n, &p->new_data, 0);
> +			if (err)
> +				return err;
> +		} else {
> +			err = dst_mirror_get_node_data(n, &p->new_data, 0);
> +			if (err)
> +				return err;
> +
> +			err = dst_mirror_write_node_data(n, &p->new_data);
> +			if (err)
> +				return err;
> +
> +			dprintk("%s: node %llu:%llu is in sync with the first node.\n",
> +					__func__, n->start, n->start+n->size);
> +		}
> +	}
> +
> +	if (!sync)
> +		dst_mirror_mark_node_notsync(n);
> +	else if (clean_on_sync)
> +		dst_mirror_mark_node_sync(n);
> +
> +	dprintk("%s: age: old: %llx, new: %llx.\n", __func__, p->old_data.age, p->new_data.age);
> +
> +	return 0;
> +}
> +
> +/*
> + * This callback is invoked when node is added to storage.
> + */
> +static int dst_mirror_add_node(struct dst_node *n)
> +{
> +	struct dst_storage *st = n->st;
> +	struct dst_mirror_priv *priv;
> +	int err = -ENOMEM, first_node = 0;
> +	u64 disk_size;
> +
> +	n->size--; /* A sector size actually. */
> +
> +	mutex_lock(&st->tree_lock);
> +	disk_size = st->disk_size;
> +	if (st->disk_size) {
> +		st->disk_size = min(n->size, st->disk_size);
> +	} else {
> +		st->disk_size = n->size;
> +		first_node = 1;
> +	}
> +	mutex_unlock(&st->tree_lock);
> +
> +	priv = kzalloc(sizeof(struct dst_mirror_priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->chunk_num = st->disk_size;
> +
> +	priv->chunk = vmalloc(DIV_ROUND_UP(priv->chunk_num, BITS_PER_LONG) * sizeof(long));
<< Ohhh. My. I want to add my 500G hdd. Do you really wanna
   say what i have to store 128Mb in memory object for this.
> +	if (!priv->chunk)
> +		goto err_out_free;
> +
> +	spin_lock_init(&priv->backlog_lock);
> +	INIT_LIST_HEAD(&priv->backlog_list);
> +
> +	dprintk("%s: %llu:%llu, chunk_num: %u, disk_size: %llu.\n\n",
> +			__func__, n->start, n->size,
> +			priv->chunk_num, st->disk_size);
> +
> +	n->priv_callback = &dst_mirror_handle_priv;
> +	n->priv = priv;
> +
> +	err = dst_mirror_ndp_setup(n, first_node, 1);
> +	if (err)
> +		goto err_out_free_chunk;
> +
> +	return 0;
> +
> +err_out_free_chunk:
> +	vfree(priv->chunk);
> +err_out_free:
> +	kfree(priv);
> +	n->priv = NULL;
> +
> +	mutex_lock(&st->tree_lock);
> +	st->disk_size = disk_size;
> +	mutex_unlock(&st->tree_lock);
> +	return err;
> +}
> +
> +static void dst_mirror_sync_destructor(struct bio *bio)
> +{
> +	struct bio_vec *bv;
> +	int i;
> +
> +	bio_for_each_segment(bv, bio, i)
> +		__free_page(bv->bv_page);
> +	bio_free(bio, dst_mirror_bio_set);
> +}
> +
> +/*
> + * Without errors it is always called under node's request lock,
> + * so it is safe to requeue them.
> + */
> +static void dst_mirror_bio_error(struct dst_request *req, int err)
> +{
> +	int i;
> +	struct dst_mirror_priv *priv = req->node->priv;
> +	unsigned int num, idx;
> +	u64 start = req->start - to_sector(req->orig_size - req->size);
> +
> +	if (err)
> +		dst_mirror_mark_notsync(req->node);
> +
> +	priv->last_start = req->start;
> +
> +	idx = start;
> +	num = to_sector(req->orig_size);
> +
> +	dprintk("%s: %llu:%llu start: %llu, size: %llu, "
> +		"chunk_num: %u, idx: %d, num: %d, err: %d, node: %p.\n",
> +		__func__, req->node->start, req->node->size,
> +		start, req->orig_size, priv->chunk_num,
> +		idx, num, err, req->node);
> +
> +	if (unlikely(idx >= priv->chunk_num || idx + num > priv->chunk_num)) {
> +		dprintk("%s: %llu:%llu req: %p, start: %llu, orig_size: %llu, "
> +			"req_start: %llu, req_size: %llu, "
> +			"chunk_num: %u, idx: %d, num: %d, err: %d.\n",
> +			__func__, req->node->start, req->node->size, req,
> +			start, req->orig_size,
> +			req->start, req->size,
> +			priv->chunk_num, idx, num, err);
> +		return;
> +	}
> +
> +	if (err) {
> +		for (i=0; i<num; ++i)
> +			__set_bit(idx+i, priv->chunk);
> +	} else {
> +		for (i=0; i<num; ++i)
> +			__clear_bit(idx+i, priv->chunk);
> +	}
> +}
> +
> +static void dst_mirror_sync_req_endio(struct dst_request *req, int err)
> +{
> +	struct dst_node *n = req->node;
> +	struct dst_mirror_priv *p = req->node->priv;
> +	int i;
> +	unsigned long notsync = 0;
> +
> +	dst_mirror_bio_error(req, err);
> +
> +	dprintk("%s: freeing bio: %p, bi_size: %u, "
> +			"orig_size: %llu, req: %p, node: %p.\n",
> +		__func__, req->bio, req->bio->bi_size, req->orig_size, req,
> +		req->node);
> +
> +	bio_put(req->bio);
> +
> +	if (!test_bit(DST_NODE_NOTSYNC, &n->flags))
> +		return;
> +
> +	for (i = 0; i < DIV_ROUND_UP(p->chunk_num, BITS_PER_LONG); ++i) {
> +		notsync = p->chunk[i];
> +		if (notsync)
> +			break;
> +	}
> +
> +	if (notsync) {
> +		dprintk("%s: %d/%d sync: %lx, ffs: %lu, chunk_num (modulo %u): %d.\n",
> +				__func__, i, DIV_ROUND_UP(p->chunk_num, BITS_PER_LONG),
> +				notsync, __ffs(notsync), BITS_PER_LONG,
> +				p->chunk_num%BITS_PER_LONG);
> +		if (i != DIV_ROUND_UP(p->chunk_num, BITS_PER_LONG) - 1)
> +			return;
> +
> +		if (__ffs(notsync) != (p->chunk_num%BITS_PER_LONG))
> +			return;
> +	}
> +
> +	dst_mirror_mark_sync(n);
> +}
> +
> +static int dst_mirror_sync_endio(struct bio *bio, unsigned int size, int err)
> +{
> +	struct dst_request *req = bio->bi_private;
> +	struct dst_node *n = req->node;
> +	struct dst_mirror_priv *priv = n->priv;
> +	unsigned long flags;
> +
> +	dprintk("%s: bio: %p, err: %d, size: %u, req: %p.\n",
> +			__func__, bio, err, bio->bi_size, req);
> +
> +	if (bio->bi_size)
> +		return 1;
> +
> +	bio->bi_rw = WRITE;
> +	bio->bi_size = req->orig_size;
> +	bio->bi_sector = req->start;
> +
> +	if (!err) {
> +		spin_lock_irqsave(&priv->backlog_lock, flags);
> +		list_add_tail(&req->request_list_entry, &priv->backlog_list);
> +		spin_unlock_irqrestore(&priv->backlog_lock, flags);
> +		kst_wake(req->state);
> +	} else {
> +		req->bio_endio(req, err);
> +		dst_free_request(req);
> +	}
> +	return 0;
> +}
> +
> +static int dst_mirror_sync_block(struct dst_node *n,
> +		int bit_start, int bit_num)
> +{
> +	u64 start = to_bytes(bit_start);
> +	u32 size = to_bytes(bit_num);
> +	struct bio *bio;
> +	unsigned int nr_pages = DIV_ROUND_UP(size, PAGE_SIZE), i;
> +	struct page *page;
> +	int err = -ENOMEM;
> +	struct dst_request *req;
> +
> +	dprintk("%s: bit_start: %d, bit_num: %d, start: %llu, nr_pages: %u, "
> +			"disk_size: %llu.\n",
> +			__func__, bit_start, bit_num, start, nr_pages,
> +			n->st->disk_size);
> +
> +	while (nr_pages) {
> +		req = dst_clone_request(NULL, n->w->req_pool);
> +		if (!req)
> +			return -ENOMEM;
> +
> +		bio = bio_alloc_bioset(GFP_NOIO, nr_pages, dst_mirror_bio_set);
> +		if (!bio)
> +			goto err_out_free_req;
> +
> +		bio->bi_rw = READ;
> +		bio->bi_private = req;
> +		bio->bi_sector = to_sector(start);
> +		bio->bi_bdev = NULL;
> +		bio->bi_destructor = dst_mirror_sync_destructor;
> +		bio->bi_end_io = dst_mirror_sync_endio;
> +
> +		for (i = 0; i < nr_pages; ++i) {
> +			err = -ENOMEM;
> +
> +			page = alloc_page(GFP_NOIO);
> +			if (!page)
> +				break;
> +
> +			err = bio_add_pc_page(n->st->queue, bio, page,
> +					min_t(u32, PAGE_SIZE, size), 0);
> +			if (err <= 0)
> +				break;
> +			size -= err;
> +			err = 0;
> +		}
> +
> +		if (err && !bio->bi_vcnt)
> +			goto err_out_put_bio;
> +
> +		req->node = n;
> +		req->state = n->state;
> +		req->start = bio->bi_sector;
> +		req->size = req->orig_size = bio->bi_size;
> +		req->bio = bio;
> +		req->idx = bio->bi_idx;
> +		req->num = bio->bi_vcnt;
> +		req->flags = DST_REQ_CHECK_QUEUE;
> +		req->offset = 0;
> +		req->bio_endio = &dst_mirror_sync_req_endio;
> +		req->callback = &kst_data_callback;
> +
> +		dprintk("%s: start: %llu, size: %llu/%u, bio: %p, req: %p, "
> +				"node: %p.\n",
> +				__func__, req->start, req->size, nr_pages, bio,
> +				req, req->node);
> +
> +		err = n->st->queue->make_request_fn(n->st->queue, bio);
<< Why direct make_request_fn instead of generic_make_request?

> +		if (err)
> +			goto err_out_put_bio;
> +
> +		nr_pages -= bio->bi_vcnt;
> +		start += bio->bi_size;
> +	}
> +
> +	return 0;
> +
> +err_out_put_bio:
> +	bio_put(bio);
> +err_out_free_req:
> +	dst_free_request(req);
> +	return err;
> +}
> +
> +/*
> + * Resync logic.
> + *
> + * System allocates and queues requests for number of regions.
> + * Each request initially is reading from the one of the nodes.
> + * When it is completed, system checks if given region was already
> + * written to, and in such case just drops read request, otherwise
> + * it writes it to the node being updated. Any write clears not-uptodate
> + * bit, which is used as a flag that region must be synchronized or not.
> + * Reading is never performed from the node under resync.
> + */
> +static int dst_mirror_resync(struct dst_node *n, int ndp)
> +{
> +	struct dst_mirror_priv *priv = n->priv;
> +	int err = 0, sync = 1, total = priv->chunk_num;
> +	unsigned int i;
> +
> +	dprintk("%s: node: %p, %llu:%llu synchronization has been started.\n",
> +			__func__, n, n->start, n->size);
> +
> +	if (ndp) {
> +		err = dst_mirror_ndp_setup(n, 0, 0);
> +		if (err)
> +			return err;
> +	}
> +
> +	for (i = 0; i < DIV_ROUND_UP(priv->chunk_num, BITS_PER_LONG); ++i) {
> +		int bit, num, start;
> +		unsigned long word = priv->chunk[i];
> +
> +		if (!word)
> +			continue;
> +
> +		num = 0;
> +		start = -1;
> +		while (word && num < BITS_PER_LONG) {
> +			bit = __ffs(word);
> +			if (start == -1)
> +				start = bit;
> +			num++;
<< MINOR_BUG: Seems you have misstyped here. AFAIU @num represent position
   of last non zero bit (start + num == last_non_zero_bit_pos)
			if (start == -1) {
                		start = bit;
                     		num = 1;
			} else
                                num += bit;

> +			word >>= (bit+1);
> +
> +			if (--total == 0)
> +				break;
> +		}
> +
> +		if (start != -1) {
> +			err = dst_mirror_sync_block(n, start + i*BITS_PER_LONG,
> +					num);
> +			if (err)
> +				break;
> +			sync = 0;
> +		}
> +
> +		if (total == 0)
> +			break;
> +	}
> +
> +	return err;
> +}
> +
> +static int dst_mirror_end_io(struct bio *bio, unsigned int size, int err)
> +{
> +	struct dst_request *req = bio->bi_private;
> +
> +	if (bio->bi_size)
> +		return 0;
> +
> +	dprintk("%s: req: %p, bio: %p, req->bio: %p, err: %d.\n",
> +			__func__, req, bio, req->bio, err);
> +	req->bio_endio(req, err);
> +	bio_put(bio);
> +	return 0;
> +}
> +
> +static void dst_mirror_read_endio(struct dst_request *req, int err)
> +{
> +	dst_mirror_bio_error(req, err);
> +
> +	if (err && req->state)
> +		kst_wake(req->state);
> +
> +	if (!err || req->callback)
> +		kst_bio_endio(req, err);
> +}
> +
> +static void dst_mirror_write_endio(struct dst_request *req, int err)
> +{
> +	dst_mirror_bio_error(req, err);
> +
> +	if (err && req->state)
> +		kst_wake(req->state);
> +
> +	req = req->priv;
> +
> +	dprintk("%s: req: %p, priv: %p err: %d, bio: %p, "
> +			"cnt: %d, orig_size: %llu.\n",
> +		__func__, req, req->priv, err, req->bio,
> +		atomic_read(&req->refcnt), req->orig_size);
> +
> +	if (atomic_dec_and_test(&req->refcnt)) {
> +		bio_endio(req->bio, req->orig_size, 0);
> +		dst_free_request(req);
> +	}
> +}
> +
> +static int dst_mirror_process_request_nosync(struct dst_request *req,
> +		struct dst_node *n)
> +{
> +	int err = 0;
> +
> +	/*
> +	 * Block layer requires to clone a bio.
> +	 */
> +	if (n->bdev) {
> +		struct bio *clone = bio_alloc_bioset(GFP_NOIO,
> +			req->bio->bi_max_vecs, dst_mirror_bio_set);
> +
> +		__bio_clone(clone, req->bio);
> +
> +		clone->bi_bdev = n->bdev;
> +		clone->bi_destructor = dst_mirror_destructor;
> +		clone->bi_private = req;
> +		clone->bi_end_io = &dst_mirror_end_io;
> +
> +		dprintk("%s: clone: %p, bio: %p, req: %p.\n",
> +				__func__, clone, req->bio, req);
> +
> +		generic_make_request(clone);
> +	} else {
> +		struct dst_request nr;
> +		/*
> +		 * Network state processing engine will clone request
> +		 * by itself if needed. We can not use the same structure
> +		 * here, since number of its fields will be modified.
> +		 */
> +		memcpy(&nr, req, sizeof(struct dst_request));
> +
> +		nr.node = n;
> +		nr.state = n->state;
> +		nr.priv = req;
> +
> +		err = kst_check_permissions(n->state, req->bio);
> +		if (!err)
> +			err = n->state->ops->push(&nr);
> +	}
> +
> +	dprintk("%s: req: %p, n: %p, bdev: %p, err: %d.\n",
> +			__func__, req, n, n->bdev, err);
> +
> +	return err;
> +}
> +
> +static void dst_mirror_sync_requeue(struct dst_node *n)
> +{
> +	struct dst_mirror_priv *p = n->priv;
> +	struct dst_request *req;
> +	unsigned int num, idx, i;
> +	u64 start;
> +	unsigned long flags;
> +	int err;
> +
> +	while (!list_empty(&p->backlog_list)) {
> +		req = NULL;
> +		spin_lock_irqsave(&p->backlog_lock, flags);
> +		if (!list_empty(&p->backlog_list)) {
> +			req = list_entry(p->backlog_list.next,
> +					struct dst_request,
> +					request_list_entry);
> +			list_del_init(&req->request_list_entry);
> +		}
> +		spin_unlock_irqrestore(&p->backlog_lock, flags);
> +
> +		if (!req)
> +			break;
> +
> +		start = req->start - to_sector(req->orig_size - req->size);
> +
> +		idx = start;
> +		num = to_sector(req->orig_size);
> +
> +		for (i=0; i<num; ++i)
> +			if (test_bit(idx+i, p->chunk))
> +				break;
> +
> +		dprintk("%s: idx: %u, num: %u, i: %u, req: %p, "
> +				"start: %llu, size: %llu.\n",
> +				__func__, idx, num, i, req,
> +				req->start, req->orig_size);
> +
> +		err = -1;
> +		if (i != num) {
> +			err = dst_mirror_process_request_nosync(req, n);
> +			if (!err)
> +				dst_free_request(req);
> +		}
> +
> +		if (err)
> +			kst_complete_req(req, err);
> +	}
> +
> +	if (!test_bit(DST_NODE_NOTSYNC, &n->flags) &&
> +			p->old_data.age != p->new_data.age) {
> +		dst_mirror_write_node_data(n, &p->new_data);
> +		p->old_data.age = p->new_data.age;
> +	}
> +}
> +
> +static int dst_mirror_process_request(struct dst_request *req,
> +		struct dst_node *n)
> +{
> +	dst_mirror_sync_requeue(n);
> +	return dst_mirror_process_request_nosync(req, n);
> +}
> +
> +static int dst_mirror_write(struct dst_request *oreq)
> +{
> +	struct dst_node *n, *node = oreq->node;
> +	struct dst_request *req;
> +	int num, err = 0, err_num = 0, orig_num;
> +
> +	req = dst_clone_request(oreq, oreq->node->w->req_pool);
> +	if (!req) {
> +		err = -ENOMEM;
> +		goto err_out_exit;
> +	}
> +
> +	req->priv = req;
> +
> +	/*
> +	 * This logic is pretty simple - req->bio_endio will not
> +	 * call bio_endio() until all mirror devices completed
> +	 * processing of the request (no matter with or without error).
> +	 * Mirror's req->bio_endio callback will take care of that.
> +	 */
> +	orig_num = num = atomic_read(&req->node->shared_num) + 1;
> +	atomic_set(&req->refcnt, num);
> +
> +	req->bio_endio = &dst_mirror_write_endio;
> +
> +	dprintk("\n%s: req: %p, mirror to %d nodes.\n",
> +			__func__, req, num);
> +
> +	err = dst_mirror_process_request(req, node);
> +	if (err)
> +		err_num++;
> +
> +	if (--num) {
> +		list_for_each_entry(n, &node->shared, shared) {
> +			dprintk("\n%s: req: %p, start: %llu, size: %llu, "
> +					"num: %d, n: %p, state: %p.\n",
> +				__func__, req, req->start,
> +				req->size, num, n, n->state);
> +
> +			err = dst_mirror_process_request(req, n);
> +			if (err)
> +				err_num++;
> +
> +			if (--num <= 0)
> +				break;
> +		}
> +	}
> +
> +	if (err_num == orig_num) {
> +		dprintk("%s: req: %p, num: %d, err: %d.\n",
> +				__func__, req, num, err);
> +		err = -ENODEV;
> +		goto err_out_exit;
> +	}
> +
> +	return 0;
> +
> +err_out_exit:
> +	return err;
> +}
> +
> +static int dst_mirror_read(struct dst_request *req)
> +{
> +	struct dst_node *node = req->node, *n, *min_dist_node;
> +	struct dst_mirror_priv *priv = node->priv;
> +	u64 dist, d;
> +	int err;
> +
> +	req->bio_endio = &dst_mirror_read_endio;
> +
> +	do {
> +		err = -ENODEV;
> +		min_dist_node = NULL;
> +		dist = -1ULL;
> +
> +		/*
> +		 * Reading is never performed from the node under resync.
> +		 * If this will cause any troubles (like all nodes must be
> +		 * resynced between each other), this check can be removed
> +		 * and per-chunk dirty bit can be tested instead.
> +		 */
> +
> +		if (!test_bit(DST_NODE_NOTSYNC, &node->flags)) {
> +			priv = node->priv;
> +			if (req->start > priv->last_start)
> +				dist = req->start - priv->last_start;
> +			else
> +				dist = priv->last_start - req->start;
> +			min_dist_node = req->node;
> +		}
> +
> +		list_for_each_entry(n, &node->shared, shared) {
> +			if (test_bit(DST_NODE_NOTSYNC, &n->flags))
> +				continue;
> +
> +			priv = n->priv;
> +
> +			if (req->start > priv->last_start)
> +				d = req->start - priv->last_start;
> +			else
> +				d = priv->last_start - req->start;
> +
> +			if (d < dist)
> +				min_dist_node = n;
> +		}
> +
> +		if (!min_dist_node)
> +			break;
> +
> +		req->node = min_dist_node;
> +		req->state = req->node->state;
> +
> +		if (req->node->bdev) {
> +			req->bio->bi_bdev = req->node->bdev;
> +			generic_make_request(req->bio);
> +			err = 0;
> +			break;
> +		}
> +
> +		err = req->state->ops->push(req);
> +		if (err) {
> +			dprintk("%s: req: %p, bio: %p, node: %p, err: %d.\n",
> +				__func__, req, req->bio, min_dist_node, err);
> +			dst_mirror_mark_notsync(req->node);
> +		}
> +	} while (err && min_dist_node);
> +
> +	if (err || !min_dist_node) {
> +		dprintk("%s: req: %p, bio: %p, node: %p, err: %d.\n",
> +			__func__, req, req->bio, min_dist_node, err);
> +		if (!err)
> +			err = -ENODEV;
> +	}
> +	dprintk("%s: req: %p, err: %d.\n", __func__, req, err);
> +	return err;
> +}
> +
> +/*
> + * This callback is invoked from block layer request processing function,
> + * its task is to remap block request to different nodes.
> + */
> +static int dst_mirror_remap(struct dst_request *req)
> +{
> +	int (*remap[])(struct dst_request *) =
> +		{&dst_mirror_read, &dst_mirror_write};
> +
> +	return remap[bio_rw(req->bio) == WRITE](req);
> +}
> +
> +static int dst_mirror_error(struct kst_state *st, int err)
> +{
> +	struct dst_request *req, *tmp;
> +	unsigned int revents = st->socket->ops->poll(NULL, st->socket, NULL);
> +
> +	dprintk("%s: err: %d, revents: %x, notsync: %d.\n",
> +			__func__, err, revents,
> +			test_bit(DST_NODE_NOTSYNC, &st->node->flags));
> +
> +	if (err == -EEXIST)
> +		return err;
> +
> +	if (!(revents & (POLLERR | POLLHUP)) &&
> +		   	(err == -EPIPE || err == -ECONNRESET)) {
> +		if (test_bit(DST_NODE_NOTSYNC, &st->node->flags)) {
> +			return dst_mirror_resync(st->node, 1);
> +		}
> +		return 0;
> +	}
> +
> +	if (atomic_read(&st->node->shared_num) == 0 &&
> +			!st->node->shared_head) {
> +		dprintk("%s: this node is the only one in the mirror, "
> +				"can not mark it notsync.\n", __func__);
> +		return err;
> +	}
> +
> +	dst_mirror_mark_notsync(st->node);
> +
> +	mutex_lock(&st->request_lock);
> +	list_for_each_entry_safe(req, tmp, &st->request_list,
> +					request_list_entry) {
> +		kst_del_req(req);
> +		dprintk("%s: requeue [%c], start: %llu, idx: %d,"
> +				" num: %d, size: %llu, offset: %u, err: %d.\n",
> +			__func__, (bio_rw(req->bio) == WRITE)?'W':'R',
> +			req->start, req->idx, req->num, req->size,
> +			req->offset, err);
> +
> +		if (bio_rw(req->bio) != WRITE) {
> +			req->start -= to_sector(req->orig_size - req->size);
> +			req->size = req->orig_size;
> +			req->flags &= ~(DST_REQ_HEADER_SENT | DST_REQ_CHEKSUM_RECV);
> +			req->idx = 0;
> +			if (dst_mirror_read(req))
> +				dst_free_request(req);
> +		} else {
> +			kst_complete_req(req, err);
> +		}
> +	}
> +	mutex_unlock(&st->request_lock);
> +	return err;
> +}
> +
> +static struct dst_alg_ops alg_mirror_ops = {
> +	.remap		= dst_mirror_remap,
> +	.add_node	= dst_mirror_add_node,
> +	.del_node	= dst_mirror_del_node,
> +	.error		= dst_mirror_error,
> +	.owner		= THIS_MODULE,
> +};
> +
> +static int __devinit alg_mirror_init(void)
> +{
> +	int err = -ENOMEM;
> +
> +	dst_mirror_bio_set = bioset_create(256, 256);
> +	if (!dst_mirror_bio_set)
> +		return -ENOMEM;
> +
> +	alg_mirror = dst_alloc_alg("alg_mirror", &alg_mirror_ops);
> +	if (!alg_mirror)
> +		goto err_out;
> +
> +	return 0;
> +
> +err_out:
> +	bioset_free(dst_mirror_bio_set);
> +	return err;
> +}
> +
> +static void __devexit alg_mirror_exit(void)
> +{
> +	dst_remove_alg(alg_mirror);
> +	bioset_free(dst_mirror_bio_set);
> +}
> +
> +module_init(alg_mirror_init);
> +module_exit(alg_mirror_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
> +MODULE_DESCRIPTION("Mirror distributed algorithm.");
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/


^ permalink raw reply

* [PATCH] r6040 various cleanups
From: Florian Fainelli @ 2007-12-12  9:44 UTC (permalink / raw)
  To: Francois Romieu, jeff; +Cc: Sten Wang, netdev

The following patch applies to Jeff's netdev-2.6 tree with Francois's r6040 recent changes pulled to this tree.

- remove unused private structure members
- functions to allocate/free TX and RX buffers
- recover from transmit timeout
- use netdev_alloc_skb instead of dev_alloc_skb
- do not use a private stats structure to store statistics
- break each TX/RX error to a separate line for better reading
- better control of the timer
- clean the IRQ handler
- fix typos and spelling mistakes in the driver

Signed-off-by: Florian Fainelli <florian.fainelli@telecomint.eu>
-- 
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 2334f4e..ff72c51 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -174,8 +174,6 @@ struct r6040_private {
 	struct net_device *dev;
 	struct mii_if_info mii_if;
 	struct napi_struct napi;
-	struct net_device_stats stats;
-	u16	napi_rx_running;
 	void __iomem *base;
 };
 
@@ -235,17 +233,54 @@ static void mdio_write(struct net_device *dev, int mii_id, int reg, int val)
 	phy_write(ioaddr, lp->phy_addr, reg, val);
 }
 
-static void r6040_tx_timeout(struct net_device *dev)
+
+static void r6040_free_txbufs(struct net_device *dev)
 {
-	struct r6040_private *priv = netdev_priv(dev);
+	struct r6040_private *lp = netdev_priv(dev);
+	int i;
 
-	disable_irq(dev->irq);
-	napi_disable(&priv->napi);
-	spin_lock(&priv->lock);
-	dev->stats.tx_errors++;
-	spin_unlock(&priv->lock);
+	for (i = 0; i < TX_DCNT; i++) {
+		if (lp->tx_insert_ptr->skb_ptr) {
+			pci_unmap_single(lp->pdev, lp->tx_insert_ptr->buf,
+				MAX_BUF_SIZE, PCI_DMA_TODEVICE);
+			dev_kfree_skb(lp->tx_insert_ptr->skb_ptr);
+			lp->rx_insert_ptr->skb_ptr = NULL;
+		}
+		lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp;
+	}
+}
 
-	netif_stop_queue(dev);
+static void r6040_free_rxbufs(struct net_device *dev)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+	int i;
+
+	for (i = 0; i < RX_DCNT; i++) {
+		if (lp->rx_insert_ptr->skb_ptr) {
+			pci_unmap_single(lp->pdev, lp->rx_insert_ptr->buf,
+				MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(lp->rx_insert_ptr->skb_ptr);
+			lp->rx_insert_ptr->skb_ptr = NULL;
+		}
+		lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp;
+	}
+}
+
+static void r6040_init_ring_desc(struct r6040_descriptor *desc_ring,
+				 dma_addr_t desc_dma, int size)
+{
+	struct r6040_descriptor *desc = desc_ring;
+	dma_addr_t mapping = desc_dma;
+
+	while (size-- > 0) {
+		mapping += sizeof(sizeof(*desc));
+		desc->ndesc = cpu_to_le32(mapping);
+		desc->vndescp = desc + 1;
+		desc++;
+	}
+	desc--;
+	desc->ndesc = cpu_to_le32(desc_dma);
+	desc->vndescp = desc_ring;
 }
 
 /* Allocate skb buffer for rx descriptor */
@@ -256,7 +291,7 @@ static void rx_buf_alloc(struct r6040_private *lp, struct net_device *dev)
 
 	descptr = lp->rx_insert_ptr;
 	while (lp->rx_free_desc < RX_DCNT) {
-		descptr->skb_ptr = dev_alloc_skb(MAX_BUF_SIZE);
+		descptr->skb_ptr = netdev_alloc_skb(dev, MAX_BUF_SIZE);
 
 		if (!descptr->skb_ptr)
 			break;
@@ -272,6 +307,63 @@ static void rx_buf_alloc(struct r6040_private *lp, struct net_device *dev)
 	lp->rx_insert_ptr = descptr;
 }
 
+static void r6040_alloc_txbufs(struct net_device *dev)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
+
+	lp->tx_free_desc = TX_DCNT;
+
+	lp->tx_remove_ptr = lp->tx_insert_ptr = lp->tx_ring;
+	r6040_init_ring_desc(lp->tx_ring, lp->tx_ring_dma, TX_DCNT);
+
+	iowrite16(lp->tx_ring_dma, ioaddr + MTD_SA0);
+	iowrite16(lp->tx_ring_dma >> 16, ioaddr + MTD_SA1);
+}
+
+static void r6040_alloc_rxbufs(struct net_device *dev)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
+
+	lp->rx_free_desc = 0;
+
+	lp->rx_remove_ptr = lp->rx_insert_ptr = lp->rx_ring;
+	r6040_init_ring_desc(lp->rx_ring, lp->rx_ring_dma, RX_DCNT);
+
+	rx_buf_alloc(lp, dev);
+
+	iowrite16(lp->rx_ring_dma, ioaddr + MRD_SA0);
+	iowrite16(lp->rx_ring_dma >> 16, ioaddr + MRD_SA1);
+}
+
+static void r6040_tx_timeout(struct net_device *dev)
+{
+	struct r6040_private *priv = netdev_priv(dev);
+	void __iomem *ioaddr = priv->base;
+
+	printk(KERN_WARNING "%s: transmit timed out, status %4.4x, PHY status "
+		"%4.4x\n",
+		dev->name, ioread16(ioaddr + MIER),
+		mdio_read(dev, priv->mii_if.phy_id, MII_BMSR));
+
+	disable_irq(dev->irq);
+	napi_disable(&priv->napi);
+	spin_lock(&priv->lock);
+	/* Clear all descriptors */
+	r6040_free_txbufs(dev);
+	r6040_free_rxbufs(dev);
+	r6040_alloc_txbufs(dev);
+	r6040_alloc_rxbufs(dev);
+
+	/* Reset MAC */
+	iowrite16(MAC_RST, ioaddr + MCR1);
+	spin_unlock(&priv->lock);
+	enable_irq(dev->irq);
+
+	dev->stats.tx_errors++;
+	netif_wake_queue(dev);
+}
 
 static struct net_device_stats *r6040_get_stats(struct net_device *dev)
 {
@@ -280,11 +372,11 @@ static struct net_device_stats *r6040_get_stats(struct net_device *dev)
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	priv->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1);
-	priv->stats.multicast += ioread8(ioaddr + ME_CNT0);
+	dev->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1);
+	dev->stats.multicast += ioread8(ioaddr + ME_CNT0);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	return &priv->stats;
+	return &dev->stats;
 }
 
 /* Stop RDC MAC and Free the allocated resource */
@@ -293,7 +385,6 @@ static void r6040_down(struct net_device *dev)
 	struct r6040_private *lp = netdev_priv(dev);
 	void __iomem *ioaddr = lp->base;
 	struct pci_dev *pdev = lp->pdev;
-	int i;
 	int limit = 2048;
 	u16 *adrp;
 	u16 cmd;
@@ -314,26 +405,10 @@ static void r6040_down(struct net_device *dev)
 	iowrite16(adrp[2], ioaddr + MID_0H);
 	free_irq(dev->irq, dev);
 	/* Free RX buffer */
-	for (i = 0; i < RX_DCNT; i++) {
-		if (lp->rx_insert_ptr->skb_ptr) {
-			pci_unmap_single(lp->pdev, lp->rx_insert_ptr->buf,
-				MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);
-			dev_kfree_skb(lp->rx_insert_ptr->skb_ptr);
-			lp->rx_insert_ptr->skb_ptr = NULL;
-		}
-		lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp;
-	}
+	r6040_free_rxbufs(dev);
 
 	/* Free TX buffer */
-	for (i = 0; i < TX_DCNT; i++) {
-		if (lp->tx_insert_ptr->skb_ptr) {
-			pci_unmap_single(lp->pdev, lp->tx_insert_ptr->buf,
-				MAX_BUF_SIZE, PCI_DMA_TODEVICE);
-			dev_kfree_skb(lp->tx_insert_ptr->skb_ptr);
-			lp->rx_insert_ptr->skb_ptr = NULL;
-		}
-		lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp;
-	}
+	r6040_free_txbufs(dev);
 
 	/* Free Descriptor memory */
 	pci_free_consistent(pdev, RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma);
@@ -432,19 +507,26 @@ static int r6040_rx(struct net_device *dev, int limit)
 
 		/* Check for errors */
 		err = ioread16(ioaddr + MLSR);
-		if (err & 0x0400) priv->stats.rx_errors++;
+		if (err & 0x0400)
+			dev->stats.rx_errors++;
 		/* RX FIFO over-run */
-		if (err & 0x8000) priv->stats.rx_fifo_errors++;
+		if (err & 0x8000)
+			dev->stats.rx_fifo_errors++;
 		/* RX descriptor unavailable */
-		if (err & 0x0080) priv->stats.rx_frame_errors++;
+		if (err & 0x0080)
+			dev->stats.rx_frame_errors++;
 		/* Received packet with length over buffer lenght */
-		if (err & 0x0020) priv->stats.rx_over_errors++;
+		if (err & 0x0020)
+			dev->stats.rx_over_errors++;
 		/* Received packet with too long or short */
-		if (err & (0x0010|0x0008)) priv->stats.rx_length_errors++;
+		if (err & 0x0010)
+			dev->stats.rx_length_errors++;
+		if (err & 0x0008)
+			dev->stats.rx_length_errors++;
 		/* Received packet with CRC errors */
 		if (err & 0x0004) {
 			spin_lock(&priv->lock);
-			priv->stats.rx_crc_errors++;
+			dev->stats.rx_crc_errors++;
 			spin_unlock(&priv->lock);
 		}
 
@@ -469,8 +551,8 @@ static int r6040_rx(struct net_device *dev, int limit)
 			/* Send to upper layer */
 			netif_receive_skb(skb_ptr);
 			dev->last_rx = jiffies;
-			priv->dev->stats.rx_packets++;
-			priv->dev->stats.rx_bytes += descptr->len;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += descptr->len;
 			/* To next descriptor */
 			descptr = descptr->vndescp;
 			priv->rx_free_desc--;
@@ -498,11 +580,15 @@ static void r6040_tx(struct net_device *dev)
 		/* Check for errors */
 		err = ioread16(ioaddr + MLSR);
 
-		if (err & 0x0200) priv->stats.rx_fifo_errors++;
-		if (err & (0x2000 | 0x4000)) priv->stats.tx_carrier_errors++;
+		if (err & 0x0200)
+			dev->stats.rx_fifo_errors++;
+		if (err & 0x2000)
+			dev->stats.tx_carrier_errors++;
+		if (err & 0x4000)
+			dev->stats.tx_carrier_errors++;
 
 		if (descptr->status & 0x8000)
-			break; /* Not complte */
+			break; /* Not complete */
 		skb_ptr = descptr->skb_ptr;
 		pci_unmap_single(priv->pdev, descptr->buf,
 			skb_ptr->len, PCI_DMA_TODEVICE);
@@ -545,7 +631,6 @@ static irqreturn_t r6040_interrupt(int irq, void *dev_id)
 	struct r6040_private *lp = netdev_priv(dev);
 	void __iomem *ioaddr = lp->base;
 	u16 status;
-	int handled = 1;
 
 	/* Mask off RDC MAC interrupt */
 	iowrite16(MSK_INT, ioaddr + MIER);
@@ -565,7 +650,7 @@ static irqreturn_t r6040_interrupt(int irq, void *dev_id)
 	if (status & 0x10)
 		r6040_tx(dev);
 
-	return IRQ_RETVAL(handled);
+	return IRQ_HANDLED;
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -577,22 +662,6 @@ static void r6040_poll_controller(struct net_device *dev)
 }
 #endif
 
-static void r6040_init_ring_desc(struct r6040_descriptor *desc_ring,
-				 dma_addr_t desc_dma, int size)
-{
-	struct r6040_descriptor *desc = desc_ring;
-	dma_addr_t mapping = desc_dma;
-
-	while (size-- > 0) {
-		mapping += sizeof(sizeof(*desc));
-		desc->ndesc = cpu_to_le32(mapping);
-		desc->vndescp = desc + 1;
-		desc++;
-	}
-	desc--;
-	desc->ndesc = cpu_to_le32(desc_dma);
-	desc->vndescp = desc_ring;
-}
 
 /* Init RDC MAC */
 static void r6040_up(struct net_device *dev)
@@ -600,30 +669,9 @@ static void r6040_up(struct net_device *dev)
 	struct r6040_private *lp = netdev_priv(dev);
 	void __iomem *ioaddr = lp->base;
 
-	/* Initialize */
-	lp->tx_free_desc = TX_DCNT;
-	lp->rx_free_desc = 0;
-	/* Init descriptor */
-	lp->tx_remove_ptr = lp->tx_insert_ptr = lp->tx_ring;
-	lp->rx_remove_ptr = lp->rx_insert_ptr = lp->rx_ring;
-	/* Init TX descriptor */
-	r6040_init_ring_desc(lp->tx_ring, lp->tx_ring_dma, TX_DCNT);
-
-	/* Init RX descriptor */
-	r6040_init_ring_desc(lp->rx_ring, lp->rx_ring_dma, RX_DCNT);
-
-	/* Allocate buffer for RX descriptor */
-	rx_buf_alloc(lp, dev);
-
-	/*
-	 * TX and RX descriptor start registers.
-	 * Lower 16-bits to MxD_SA0. Higher 16-bits to MxD_SA1.
-	 */
-	iowrite16(lp->tx_ring_dma, ioaddr + MTD_SA0);
-	iowrite16(lp->tx_ring_dma >> 16, ioaddr + MTD_SA1);
-
-	iowrite16(lp->rx_ring_dma, ioaddr + MRD_SA0);
-	iowrite16(lp->rx_ring_dma >> 16, ioaddr + MRD_SA1);
+	/* Initialise and alloc RX/TX buffers */
+	r6040_alloc_txbufs(dev);
+	r6040_alloc_rxbufs(dev);
 
 	/* Buffer Size Register */
 	iowrite16(MAX_BUF_SIZE, ioaddr + MR_BSR);
@@ -689,8 +737,7 @@ static void r6040_timer(unsigned long data)
 	}
 
 	/* Timer active again */
-	lp->timer.expires = TIMER_WUT;
-	add_timer(&lp->timer);
+	mod_timer(&lp->timer, jiffies + round_jiffies(HZ));
 }
 
 /* Read/set MAC address routines */
@@ -746,14 +793,10 @@ static int r6040_open(struct net_device *dev)
 	napi_enable(&lp->napi);
 	netif_start_queue(dev);
 
-	if (lp->switch_sig != ICPLUS_PHY_ID) {
-		/* set and active a timer process */
-		init_timer(&lp->timer);
-		lp->timer.expires = TIMER_WUT;
-		lp->timer.data = (unsigned long)dev;
-		lp->timer.function = &r6040_timer;
-		add_timer(&lp->timer);
-	}
+	/* set and active a timer process */
+	setup_timer(&lp->timer, r6040_timer, (unsigned long) dev);
+	if (lp->switch_sig != ICPLUS_PHY_ID)
+		mod_timer(&lp->timer, jiffies + HZ);
 	return 0;
 }

^ permalink raw reply related

* Re: [4/4] DST: Algorithms used in distributed storage.
From: Evgeniy Polyakov @ 2007-12-12 10:20 UTC (permalink / raw)
  To: lkml, netdev, linux-fsdevel
In-Reply-To: <20071212091246.GA12871@dmon-lap.sw.ru>

On Wed, Dec 12, 2007 at 12:12:47PM +0300, Dmitry Monakhov (dmonakhov@sw.ru) wrote:
> On 14:47 Mon 10 Dec     , Evgeniy Polyakov wrote:
> > 
> > Algorithms used in distributed storage.
> > Mirror and linear mapping code.
> Hi, i've finally take a look on your DST solution.
> It seems what your current implementation will not work on nonstandard
> devices for example software raid0.
> other comments are follows:

> > +static int dst_mirror_process_node_data(struct dst_node *n,
> > +		struct dst_mirror_node_data *ndata, int op)

> > +
> > +	kunmap(cmp->page);
> << MINOR_BUG:
>    You has forgot to unmap page on error path, so IMHO it is better to move
>    kunmap to "err_out_free_cmp" label.

Yep, I will fix this.

> > +	priv = kzalloc(sizeof(struct dst_mirror_priv), GFP_KERNEL);
> > +	if (!priv)
> > +		return -ENOMEM;
> > +
> > +	priv->chunk_num = st->disk_size;
> > +
> > +	priv->chunk = vmalloc(DIV_ROUND_UP(priv->chunk_num, BITS_PER_LONG) * sizeof(long));
> << Ohhh. My. I want to add my 500G hdd. Do you really wanna
>    say what i have to store 128Mb in memory object for this.

Right now yes. There was a code which used single bit for bigger
data units, but I dropped it because of resync troubles (i.e. when
one single sector has been updated, it requires to resync the whole
block). I can not say which case is better though.

> > +		dprintk("%s: start: %llu, size: %llu/%u, bio: %p, req: %p, "
> > +				"node: %p.\n",
> > +				__func__, req->start, req->size, nr_pages, bio,
> > +				req, req->node);
> > +
> > +		err = n->st->queue->make_request_fn(n->st->queue, bio);
> << Why direct make_request_fn instead of generic_make_request?

generic_make_request() will queue the bio in this case,
so I call request_fn directly.

> > +	for (i = 0; i < DIV_ROUND_UP(priv->chunk_num, BITS_PER_LONG); ++i) {
> > +		int bit, num, start;
> > +		unsigned long word = priv->chunk[i];
> > +
> > +		if (!word)
> > +			continue;
> > +
> > +		num = 0;
> > +		start = -1;
> > +		while (word && num < BITS_PER_LONG) {
> > +			bit = __ffs(word);
> > +			if (start == -1)
> > +				start = bit;
> > +			num++;
> << MINOR_BUG: Seems you have misstyped here. AFAIU @num represent position
>    of last non zero bit (start + num == last_non_zero_bit_pos)
> 			if (start == -1) {
>                 		start = bit;
>                      		num = 1;
> 			} else
>                                 num += bit;

Yes, you are right of course.
Since I shift word to more than a single bit, @num has to be update
accordingly.

> > +			word >>= (bit+1);

Dmitry, thanks a lot for comments, I will fix issues you pointed in the
next release, although will stay bitmap case opened for a while.

-- 
	Evgeniy Polyakov

^ permalink raw reply

* [PATCH 2.6.25] netns: network namespace was passed into dev_getbyhwaddr but not used
From: Denis V. Lunev @ 2007-12-12 11:05 UTC (permalink / raw)
  To: davem; +Cc: containers, devel, netdev

netns: network namespace was passed into dev_getbyhwaddr but not used

Signed-off-by: Denis V. Lunev <den@openvz.org>
diff --git a/net/core/dev.c b/net/core/dev.c
index 06615df..677f35b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -675,7 +675,7 @@ struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type, char *h
 
 	ASSERT_RTNL();
 
-	for_each_netdev(&init_net, dev)
+	for_each_netdev(net, dev)
 		if (dev->type == type &&
 		    !memcmp(dev->dev_addr, ha, dev->addr_len))
 			return dev;

^ permalink raw reply related

* [PATCH 2.6.25] IPv4: thresholds in fib_trie.c are not modified, make them const
From: Denis V. Lunev @ 2007-12-12 11:05 UTC (permalink / raw)
  To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
  Cc: containers-qjLDD68F18O7TbgM5vRIOg, netdev-u79uwXL29TY76Z2rM5mHXA

IPv4: thresholds in fib_trie.c are not modified, make them const

Signed-off-by: Denis V. Lunev <den-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 45a6e4d..57a2c46 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -299,10 +299,10 @@ static inline void check_tnode(const struct tnode *tn)
 	WARN_ON(tn && tn->pos+tn->bits > 32);
 }
 
-static int halve_threshold = 25;
-static int inflate_threshold = 50;
-static int halve_threshold_root = 15;
-static int inflate_threshold_root = 25;
+static const int halve_threshold = 25;
+static const int inflate_threshold = 50;
+static const int halve_threshold_root = 15;
+static const int inflate_threshold_root = 25;
 
 static void __alias_free_mem(struct rcu_head *head)
 {

^ permalink raw reply related

* Re: [kvm-devel] [PATCH resent] virtio_net: Fix stalled inbound trafficon early packets
From: Christian Borntraeger @ 2007-12-12 11:27 UTC (permalink / raw)
  To: dor.laor; +Cc: Rusty Russell, kvm-devel, netdev, virtualization
In-Reply-To: <475F1E86.8000503@qumranet.com>

Am Mittwoch, 12. Dezember 2007 schrieb Dor Laor:
> This is why initially I suggested another status code in order to split 
> the ring logic with driver status.
> > but also not filling any buffers as long as VIRTIO_CONFIG_DEV_OPEN is 
not 
> > set. I will have a look but I think that add_status needs to be called 
> >   
> It can fill the buffers even without dev_open, when the dev is finally 
> opened the host will issue an interrupt if there are pending buffers. 

There is a problem associated with that scheme. Setting the value in the 
config space does not notify the hypervisor. That means the host will not 
send an interrupt. The interrupt is sent if the host tries to send the next 
packet. If somehow the host manages to use up all buffers before the device 
is finally opened, we have a problem.
> (I'm not sure it's worth solving, maybe  just drop them like you 
suggested).
As said above, dropping seems to me the preferred method. Did I miss 
something?

Christian

^ permalink raw reply

* Re: [kvm-devel] [PATCH resent] virtio_net: Fix stalled inbound trafficon early packets
From: Christian Borntraeger @ 2007-12-12 11:39 UTC (permalink / raw)
  To: Rusty Russell; +Cc: dor.laor, kvm-devel, netdev, virtualization
In-Reply-To: <200712121254.13865.rusty@rustcorp.com.au>

Am Mittwoch, 12. Dezember 2007 schrieb Rusty Russell:
> On Wednesday 12 December 2007 00:16:12 Christian Borntraeger wrote:
> > That would also work. We already have VRING_AVAIL_F_NO_INTERRUPT in
> > virtio_ring.c - maybe we can use that. Its hidden in callback and
> > restart handling, what about adding an explicit startup?
> 
> Yes, I debated whether to make this a separate hook or not; the current
> method  reduces the number of function calls without having two ways of
> disabling  callbacks.
> 
> In this case, simply starting devices with callbacks disabled and 
> renaming 'restart' to 'enable' (or something) and calling it at the
> beginning is probably sufficient?

So you suggest something like the following patch? It seems to work but 
there is still a theoretical race at startup. Therefore, I tend to agree 
with Dor that a separate hook seems prefereable, so I am not fully sure if 
the patch is the final solution:

ps: Its ok to answer that after your vacation. 

---
 drivers/block/virtio_blk.c   |    3 ++-
 drivers/net/virtio_net.c     |    5 ++++-
 drivers/virtio/virtio_ring.c |    9 ++++-----
 include/linux/virtio.h       |    4 ++--
 4 files changed, 12 insertions(+), 9 deletions(-)

Index: kvm/drivers/virtio/virtio_ring.c
===================================================================
--- kvm.orig/drivers/virtio/virtio_ring.c
+++ kvm/drivers/virtio/virtio_ring.c
@@ -220,7 +220,7 @@ static void *vring_get_buf(struct virtqu
 	return ret;
 }
 
-static bool vring_restart(struct virtqueue *_vq)
+static bool vring_enable(struct virtqueue *_vq)
 {
 	struct vring_virtqueue *vq = to_vvq(_vq);
 
@@ -264,7 +264,7 @@ static struct virtqueue_ops vring_vq_ops
 	.add_buf = vring_add_buf,
 	.get_buf = vring_get_buf,
 	.kick = vring_kick,
-	.restart = vring_restart,
+	.enable = vring_enable,
 	.shutdown = vring_shutdown,
 };
 
@@ -299,9 +299,8 @@ struct virtqueue *vring_new_virtqueue(un
 	vq->in_use = false;
 #endif
 
-	/* No callback?  Tell other side not to bother us. */
-	if (!callback)
-		vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+	/* disable interrupts until we enable them */
+	vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
 
 	/* Put everything in free lists. */
 	vq->num_free = num;
Index: kvm/include/linux/virtio.h
===================================================================
--- kvm.orig/include/linux/virtio.h
+++ kvm/include/linux/virtio.h
@@ -41,7 +41,7 @@ struct virtqueue
  *	vq: the struct virtqueue we're talking about.
  *	len: the length written into the buffer
  *	Returns NULL or the "data" token handed to add_buf.
- * @restart: restart callbacks after callback returned false.
+ * @enable: restart callbacks after callback returned false.
  *	vq: the struct virtqueue we're talking about.
  *	This returns "false" (and doesn't re-enable) if there are pending
  *	buffers in the queue, to avoid a race.
@@ -65,7 +65,7 @@ struct virtqueue_ops {
 
 	void *(*get_buf)(struct virtqueue *vq, unsigned int *len);
 
-	bool (*restart)(struct virtqueue *vq);
+	bool (*enable)(struct virtqueue *vq);
 
 	void (*shutdown)(struct virtqueue *vq);
 };
Index: kvm/drivers/net/virtio_net.c
===================================================================
--- kvm.orig/drivers/net/virtio_net.c
+++ kvm/drivers/net/virtio_net.c
@@ -201,7 +201,7 @@ again:
 	/* Out of packets? */
 	if (received < budget) {
 		netif_rx_complete(vi->dev, napi);
-		if (unlikely(!vi->rvq->vq_ops->restart(vi->rvq))
+		if (unlikely(!vi->rvq->vq_ops->enable(vi->rvq))
 		    && netif_rx_reschedule(vi->dev, napi))
 			goto again;
 	}
@@ -292,6 +292,9 @@ static int virtnet_open(struct net_devic
 		return -ENOMEM;
 
 	napi_enable(&vi->napi);
+
+	vi->rvq->vq_ops->enable(vi->rvq);
+	vi->svq->vq_ops->enable(vi->svq);
 	return 0;
 }
 
Index: kvm/drivers/block/virtio_blk.c
===================================================================
--- kvm.orig/drivers/block/virtio_blk.c
+++ kvm/drivers/block/virtio_blk.c
@@ -183,7 +183,8 @@ static int virtblk_probe(struct virtio_d
 		err = PTR_ERR(vblk->vq);
 		goto out_free_vblk;
 	}
-
+	/* enable interrupts */
+	vblk->vq->vq_ops->enable(vblk->vq);
 	vblk->pool = mempool_create_kmalloc_pool(1,sizeof(struct virtblk_req));
 	if (!vblk->pool) {
 		err = -ENOMEM;


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox