* (unknown),
From: Madalin Bucur @ 2011-12-20 16:06 UTC (permalink / raw)
To: steffen.klassert; +Cc: davem, eric.dumazet, timo.teras, netdev
Hi Steffen,
I did not have the time to test and send a v2 for my patch to remove the leftover local_bh_disable()/local_bh_enable() Ben has spotted.
I've also tried to use your approach but in my tests, under high load, the defered work was defered forever...
I'll try to test again with your patch and confirm it does not suffer from this issue or send a patch with those local_bh removed.
Madalin
-----Original Message-----
From: Steffen Klassert [mailto:steffen.klassert@secunet.com]
Sent: Tuesday, December 20, 2011 10:24 AM
To: David Miller
Cc: Bucur Madalin-Cristian-B32716; eric.dumazet@gmail.com; netdev@vger.kernel.org; timo.teras@iki.fi
Subject: Re: [PATCH] net/flow: remove sleeping and deferral mechanism from flow_cache_flush
On Tue, Sep 27, 2011 at 03:31:32PM -0400, David Miller wrote:
> From: David Miller <davem@davemloft.net>
> Date: Tue, 27 Sep 2011 15:28:36 -0400 (EDT)
>
> > afinfo->garbage_collect is the only other place
> > afinfo->__xfrm_garbage_collect
> > is referenced, and that is completely unused and should thus be
> > deleted (I'll take care of that in net-next).
>
> Nevermind I see how these are referenced directly via xfrm4_policy.c
> and xfrm6_policy.c, sigh...
Is there any progress in fixing this issue? I've seen this occasionally on some of our production systems, so I fixed it for us in the meantime with the patch below. I could submit this for inclusion if noone else wants to fix it in a different manner.
^ permalink raw reply
* RE: [PATCH 1/2] tcp: refactor tcp_retransmit_skb() for a single return point
From: Satoru Moriya @ 2011-12-20 16:55 UTC (permalink / raw)
To: David Laight, netdev@vger.kernel.org
Cc: nhorman@tuxdriver.com, davem@davemloft.net, tgraf@infradead.org,
Seiji Aguchi, dle-develop@lists.sourceforge.net
In-Reply-To: <AE90C24D6B3A694183C094C60CF0A2F6D8AF19@saturn3.aculab.com>
On 12/19/2011 07:10 AM, David Laight wrote:
>
>> This is just a cleanup patch for making easy to hook return value
>> with a tracepoint.
>
> Another way to temporarily add such a trace, is to temporarily
> add a wrapper function.
I'm afraid that I don't know how to add a wrapper function temporarily.
Could you please tell me how to do that? Jprobe?
Regards,
Satoru
^ permalink raw reply
* Re: [PATCH] net/sched: sch_plug - Queue traffic until an explicit release command
From: Shriram Rajagopalan @ 2011-12-20 17:05 UTC (permalink / raw)
To: Jamal Hadi Salim; +Cc: netdev, Brendan Cully
In-Reply-To: <1324391902.17751.227.camel@mojatatu>
On Tue, Dec 20, 2011 at 8:38 AM, Jamal Hadi Salim <jhs@mojatatu.com> wrote:
>
> Sorry - I didnt see your earlier CC. Cyberus.ca is probably the
> worst service provider in Canada (maybe the world; i am sure there
> are better ISPs in the middle of an ocean somewhere, deep underwater
> probably).
>
> On Mon, 2011-12-19 at 13:22 -0800, rshriram@cs.ubc.ca wrote:
>> This qdisc can be used to implement output buffering, an essential
>> functionality required for consistent recovery in checkpoint based
>> fault tolerance systems.
>
> I am trying to figure where this qdisc runs - is it in the hypervisor?
>
In dom0. Basically the setup is like this:
Guest (veth0)
dom0 (vif0.0 --> eth0)
packets coming out of veth0 appear as incoming packets in vif0.0
Once Remus (or any other output commit style system is started)
the following commands could be executed in dom0, to activate this qdisc
ip link set ifb0 up
tc qdisc add dev vif0.0 ingress
tc filter add dev vif0.0 parent ffff: proto ip pref 10 u32 match u32
0 0 action mirred egress redirect dev eth0
>> The qdisc supports two operations - plug and
>> unplug. When the qdisc receives a plug command via netlink request,
>> packets arriving henceforth are buffered until a corresponding unplug
>> command is received.
>
> Ok, so plug indicates "start of checkpoint" and unplug the end.
> Seems all you want is at a certain point to throttle the qdisc and
> later on unplug/unthrottle, correct?
> Sounds to me like a generic problem that applies to all qdiscs?
>
Oh yes. But throttle functionality doesnt seem to be implemented
in the qdisc code base. there is a throttle flag but looking at the
qdisc scheduler, I could see no references to this flag or related actions.
That is why in the dequeue function, I return NULL until the release pointer
is set.
And we need a couple of netlink api calls (PLUG/UNPLUG) to manipulate
the qdisc from userspace
>> Its intention is to support speculative execution by allowing generated
>> network traffic to be rolled back. It is used to provide network
>> protection for domUs in the Remus high availability project, available as
>> part of Xen. This module is generic enough to be used by any other
>> system that wishes to add speculative execution and output buffering to
>> its applications.
>
> Should get a nice demo effect of showing a simple ping working with
> zero drops,
I have done better. When Remus is activated for a Guest VM, I pull the
plug from the primary physical host and the ssh connection to the domU,
with top command running (and/or xeyes) continues to run seamlessly. ;)
>but: what is the effect of not even having this qdisc?
When the guest VM recovers on another physical host, it is restored to the
most recent checkpoint. With a checkpoint frequency of 25ms, in the worst case
on failover, one checkpoint worth of execution could be lost. With the loss of
the physical machine and its output buffer, the packets (tcp,udp, etc)
are also lost.
But that does not affect the "consistency" of the state of Guest and
client connections,
as the client (say TCP clients) only think that there was some packet
loss and "resend"
the packets. The resuming Guest VM on the backup host would pickup the
connection
from where it left off.
OTOH, if the packets were released before the checkpoint was done,
then we have the
classic orphaned messages problem. If the client and the Guest VM
exchange a bunch
of packets, the TCP window moves. When the Guest VM resumes on the backup host,
it is basically rolled back in time (by 25ms or so), i.e. it does not
know about the shift
in the tcp window. Hence, the client and Guest's tcp sequence numbers
would be out of
sync and the connection would hang. For other protocols like UDP etc,
the "unmodified"
client may be capable of handling packet losses but not the server
application forgetting
about stuff it had acknowledged.
> If you just switch the qdisc to a sleeping state from user space, all
> packets arriving at that qdisc will be dropped during the checkpoint
> phase (and the kernel code will be tiny or none).
Which we dont want. I want to buffer the packets and then release them
once the checkpoint is committed at the backup host.
> If you do nothing some packets will be buffered and a watchdog
> will recover them when conditions become right.
Doing nothing is sort of what this qdisc does, so that the packets
get buffered. The watchdog in this case is the user space process
that sends the netlink command UNPLUG to release the packets.
(aka conditions become right).
One could do this with any qdisc but the catch here is that the qdisc
stops releasing packets only when it hits the stop pointer (ie start of
the next checkpoint buffer). Simply putting a qdisc to sleep would
prevent it from releasing packets from the current buffer (whose checkpoint
has been acked).
> So does this qdisc add anything different?
>
> [Note: In your case when arriving packets find the queue filled up
> you will drop lotsa packets - depending on traffic patterns; so
> not much different than above]
>
>> +
>> +#define FIFO_BUF (10*1024*1024)
>
> Aha.
> Technically - use tc to do this. Conceptually:
> This is probably what makes you look good in a demo if you have one;
> huge freaking buffer. If you are doing a simple ping (or a simple
> interactive session like ssh) and you can failover in 5 minutes you
> still wont be able to fill that buffer!
>
I agree. Its more sensible to configure it via the tc command. I would
probably have to end up issuing patches for the tc code base too.
> Look at the other feedback given to you (Stephen and Dave responded).
>
> If a qdisc is needed, should it not be a classful qdisc?
>
I dont understand. why ?
shriram
> cheers,
> jamal
>
^ permalink raw reply
* Re: [PATCH] sctp: Do not account for sizeof(struct sk_buff) in estimated rwnd
From: Vlad Yasevich @ 2011-12-20 18:01 UTC (permalink / raw)
To: Wei Yongjun, linux-sctp, davem, netdev
In-Reply-To: <20111220093910.GB21801@canuck.infradead.org>
On 12/20/2011 04:39 AM, Thomas Graf wrote:
> On Tue, Dec 20, 2011 at 01:00:48PM +0800, Wei Yongjun wrote:
>> I saw you discussed this with Vlad in old mail:
>> http://www.spinics.net/lists/linux-sctp/msg01365.html
>>
>> You said you will update patch to include a per packet overhead,
>> but it does not include in this patch, what's wrong with in?
>
> It's not possible because upon retransmission of a chunk we need
> to readd the overhead to the rwnd. There is no longer a reference
> to a packet so we can't know how much to add. This explanation is
> also in the original mail thread.
>
Right. The original patches were done to work around the problem of
leftover rwnd when socket buffer is exhausted and they didn't really
address the problem sufficiently. It was still possible to reach that
condition. Some subsequent patches added support to address this issue
a different way. As a result, I think this revert is just fine.
Acked-by: Vlad Yasevich <vladislav.yasevich@hp.com>
-vlad
^ permalink raw reply
* [PATCH v3] ARM: net: JIT compiler for packet filters
From: Mircea Gherzan @ 2011-12-20 18:04 UTC (permalink / raw)
To: linux-arm-kernel; +Cc: mgherzan, netdev, linux
Based of Matt Evans's PPC64 implementation.
The compiler generates ARM instructions but interworking is
supported for Thumb2 kernels.
Supports both little and big endian. Unaligned loads are emitted
for ARMv6+. Not all the BPF opcodes that deal with ancillary data
are supported. The scratch memory of the filter lives on the stack.
Hardware integer division is used if it is available.
Enabled in the same way as for x86-64 and PPC64:
echo 1 > /proc/sys/net/core/bpf_jit_enable
A value greater than 1 enables opcode output.
Signed-off-by: Mircea Gherzan <mgherzan@gmail.com>
---
Changes in v3:
* no longer depend on EABI and !Thumb2
* add BLX "emulation" for ARMv4 without Thumb
* use the integer divide instruction on Cortex-A15
* fix the handling of the DIV_K opcode
* use a C wrapper for __aeabi_uidiv
* fix the generation of the epilogue (non-FP case)
Changes in v2:
* enable the compiler ony for ARMv5+ because of the BLX instruction
* use the same comparison for the ARM version checks
* use misaligned accesses on ARMv6
* fix the SEEN_MEM
* fix the mem_words_used()
arch/arm/Kconfig | 1 +
arch/arm/Makefile | 1 +
arch/arm/net/Makefile | 3 +
arch/arm/net/bpf_jit_32.c | 876 +++++++++++++++++++++++++++++++++++++++++++++
arch/arm/net/bpf_jit_32.h | 180 ++++++++++
5 files changed, 1061 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/net/Makefile
create mode 100644 arch/arm/net/bpf_jit_32.c
create mode 100644 arch/arm/net/bpf_jit_32.h
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index abba5b8..0014b4b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -30,6 +30,7 @@ config ARM
select HAVE_SPARSE_IRQ
select GENERIC_IRQ_SHOW
select CPU_PM if (SUSPEND || CPU_IDLE)
+ select HAVE_BPF_JIT
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index dfcf3b0..8810a10 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -255,6 +255,7 @@ core-$(CONFIG_VFP) += arch/arm/vfp/
# If we have a machine-specific directory, then include it in the build.
core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
+core-y += arch/arm/net/
core-y += $(machdirs) $(platdirs)
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
diff --git a/arch/arm/net/Makefile b/arch/arm/net/Makefile
new file mode 100644
index 0000000..c2c1084
--- /dev/null
+++ b/arch/arm/net/Makefile
@@ -0,0 +1,3 @@
+# ARM-specific networking code
+
+obj-$(CONFIG_BPF_JIT) += bpf_jit_32.o
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
new file mode 100644
index 0000000..6e39e80
--- /dev/null
+++ b/arch/arm/net/bpf_jit_32.c
@@ -0,0 +1,876 @@
+/*
+ * Just-In-Time compiler for BPF filters on 32bit ARM
+ *
+ * Copyright (c) 2011 Mircea Gherzan <mgherzan@gmail.com>
+ *
+ * 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; version 2 of the License.
+ */
+
+#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/filter.h>
+#include <linux/moduleloader.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/cacheflush.h>
+#include <asm/hwcap.h>
+
+#include "bpf_jit_32.h"
+
+/*
+ * ABI:
+ *
+ * r0 scratch register
+ * r4 BPF register A
+ * r5 BPF register X
+ * r6 pointer to the skb
+ * r7 skb->data
+ * r8 skb_headlen(skb)
+ */
+
+#define r_scratch ARM_R0
+/* r1-r3 are (also) used for the unaligned loads on the non-ARMv7 slowpath */
+#define r_off ARM_R1
+#define r_A ARM_R4
+#define r_X ARM_R5
+#define r_skb ARM_R6
+#define r_skb_data ARM_R7
+#define r_skb_hl ARM_R8
+
+#define SCRATCH_SP_OFFSET 0
+#define SCRATCH_OFF(k) (SCRATCH_SP_OFFSET + (k))
+
+#define SEEN_MEM ((1 << BPF_MEMWORDS) - 1)
+#define SEEN_MEM_WORD(k) (1 << (k))
+#define SEEN_X (1 << BPF_MEMWORDS)
+#define SEEN_CALL (1 << (BPF_MEMWORDS + 1))
+#define SEEN_DATA (1 << (BPF_MEMWORDS + 2))
+#define SEEN_LEN (1 << (BPF_MEMWORDS + 3))
+
+struct jit_ctx {
+ const struct sk_filter *skf;
+ unsigned idx;
+ unsigned prologue_bytes;
+ int ret0_fp_idx;
+ u32 seen;
+ u32 *offsets;
+ u32 *target;
+#if __LINUX_ARM_ARCH__ < 7
+ u16 epilogue_bytes;
+ u16 imm_count;
+ u32 *imms;
+#endif
+};
+
+int bpf_jit_enable __read_mostly;
+
+static u8 jit_get_skb_b(struct sk_buff *skb, unsigned offset)
+{
+ u8 ret;
+ skb_copy_bits(skb, offset, &ret, 1);
+ return ret;
+}
+
+static u16 jit_get_skb_h(struct sk_buff *skb, unsigned offset)
+{
+ u16 ret;
+ skb_copy_bits(skb, offset, &ret, 2);
+ return ntohs(ret);
+}
+
+static u32 jit_get_skb_w(struct sk_buff *skb, unsigned offset)
+{
+ u32 ret;
+ skb_copy_bits(skb, offset, &ret, 4);
+ return ntohl(ret);
+}
+
+/*
+ * Wrapper that handles both OABI and EABI and assures Thumb2 interworking
+ * (where the assembly routines like __aeabi_uidiv could cause problems).
+ */
+static u32 jit_udiv(u32 dividend, u32 divisor)
+{
+ return dividend / divisor;
+}
+
+static inline void _emit(int cond, u32 inst, struct jit_ctx *ctx)
+{
+ if (ctx->target != NULL)
+ ctx->target[ctx->idx] = inst | (cond << 28);
+
+ ctx->idx++;
+}
+
+/*
+ * Emit an instruction that will be executed unconditionally.
+ */
+static inline void emit(u32 inst, struct jit_ctx *ctx)
+{
+ _emit(ARM_COND_AL, inst, ctx);
+}
+
+static u16 saved_regs(struct jit_ctx *ctx)
+{
+ u16 ret = 0;
+
+ if (ctx->skf->len > 1)
+ ret |= 1 << r_A;
+
+#ifdef CONFIG_FRAME_POINTER
+ ret |= (1 << ARM_FP) | (1 << ARM_IP) | (1 << ARM_LR) | (1 << ARM_PC);
+#else
+ if (ctx->seen & SEEN_CALL)
+ ret |= 1 << ARM_LR;
+#endif
+ if (ctx->seen & (SEEN_DATA | SEEN_LEN))
+ ret |= 1 << r_skb;
+ if (ctx->seen & SEEN_DATA)
+ ret |= (1 << r_skb_data) | (1 << r_skb_hl);
+ if (ctx->seen & SEEN_X)
+ ret |= 1 << r_X;
+
+ return ret;
+}
+
+static inline int mem_words_used(struct jit_ctx *ctx)
+{
+ u32 words = ctx->seen & SEEN_MEM;
+ /* yes, we do waste some stack space IF there are "holes" in the set" */
+ return 32 - __builtin_clz(words);
+}
+
+static inline bool is_load_to_a(u16 inst)
+{
+ switch (inst) {
+ case BPF_S_LD_W_LEN:
+ case BPF_S_LD_W_ABS:
+ case BPF_S_LD_H_ABS:
+ case BPF_S_LD_B_ABS:
+ case BPF_S_ANC_CPU:
+ case BPF_S_ANC_IFINDEX:
+ case BPF_S_ANC_MARK:
+ case BPF_S_ANC_PROTOCOL:
+ case BPF_S_ANC_RXHASH:
+ case BPF_S_ANC_QUEUE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void build_prologue(struct jit_ctx *ctx)
+{
+ u16 reg_set = saved_regs(ctx);
+ u16 first_inst = ctx->skf->insns[0].code;
+ u16 off;
+
+#ifdef CONFIG_FRAME_POINTER
+ emit(ARM_MOV_R(ARM_IP, ARM_SP), ctx);
+ emit(ARM_PUSH(reg_set), ctx);
+ emit(ARM_SUB_I(ARM_FP, ARM_IP, 4), ctx);
+#else
+ if (reg_set)
+ emit(ARM_PUSH(reg_set), ctx);
+#endif
+
+ if (ctx->seen & (SEEN_DATA | SEEN_LEN))
+ emit(ARM_MOV_R(r_skb, ARM_R0), ctx);
+
+ if (ctx->seen & SEEN_DATA) {
+ off = offsetof(struct sk_buff, data);
+ emit(ARM_LDR_I(r_skb_data, r_skb, off), ctx);
+ /* headlen = len - data_len */
+ off = offsetof(struct sk_buff, len);
+ emit(ARM_LDR_I(r_skb_hl, r_skb, off), ctx);
+ off = offsetof(struct sk_buff, data_len);
+ emit(ARM_LDR_I(r_scratch, r_skb, off), ctx);
+ emit(ARM_SUB_R(r_skb_hl, r_skb_hl, r_scratch), ctx);
+ }
+
+ if (ctx->seen & SEEN_X)
+ emit(ARM_MOV_I(r_X, 0), ctx);
+
+ /* do not leak kernel data to userspace */
+ if ((first_inst != BPF_S_RET_K) && !(is_load_to_a(first_inst)))
+ emit(ARM_MOV_I(r_A, 0), ctx);
+
+ /* stack space for the BPF_MEM words */
+ if (ctx->seen & SEEN_MEM)
+ emit(ARM_SUB_I(ARM_SP, ARM_SP, mem_words_used(ctx) * 4), ctx);
+}
+
+static void build_epilogue(struct jit_ctx *ctx)
+{
+ u16 reg_set = saved_regs(ctx);
+
+ if (ctx->seen & SEEN_MEM)
+ emit(ARM_ADD_I(ARM_SP, ARM_SP, mem_words_used(ctx) * 4), ctx);
+
+ reg_set &= ~(1 << ARM_LR);
+
+#ifdef CONFIG_FRAME_POINTER
+ /* the first instruction of the prologue was: mov ip, sp */
+ reg_set &= ~(1 << ARM_IP);
+ reg_set |= (1 << ARM_SP);
+ emit(ARM_LDM(ARM_SP, reg_set), ctx);
+#else
+ if (ctx->seen) {
+ if (ctx->seen & SEEN_CALL)
+ reg_set |= 1 << ARM_PC;
+ emit(ARM_POP(reg_set), ctx);
+ }
+
+ if (!(ctx->seen & SEEN_CALL))
+ emit(ARM_BX(ARM_LR), ctx);
+#endif
+}
+
+static int16_t imm8m(u32 x)
+{
+ u32 rot;
+
+ for (rot = 0; rot < 16; rot++)
+ if ((x & ~ror32(0xff, 2 * rot)) == 0)
+ return rol32(x, 2 * rot) | (rot << 8);
+
+ return -1;
+}
+
+#if __LINUX_ARM_ARCH__ < 7
+
+static u16 imm_offset(u32 k, struct jit_ctx *ctx)
+{
+ unsigned i = 0, offset;
+ u16 imm;
+
+ /* on the "fake" run we just count them (duplicates included) */
+ if (ctx->target == NULL) {
+ ctx->imm_count++;
+ return 0;
+ }
+
+ while ((i < ctx->imm_count) && ctx->imms[i]) {
+ if (ctx->imms[i] == k)
+ break;
+ i++;
+ }
+
+ if (ctx->imms[i] == 0)
+ ctx->imms[i] = k;
+
+ /* constants go just after the epilogue */
+ offset = ctx->offsets[ctx->skf->len];
+ offset += ctx->prologue_bytes;
+ offset += ctx->epilogue_bytes;
+ offset += i * 4;
+
+ ctx->target[offset / 4] = k;
+
+ /* PC in ARM mode == address of the instruction + 8 */
+ imm = offset - (8 + ctx->idx * 4);
+
+ return imm;
+}
+
+#endif /* __LINUX_ARM_ARCH__ */
+
+/*
+ * Move an immediate that's not an imm8m to a core register.
+ */
+static inline void emit_mov_i_no8m(int rd, u32 val, struct jit_ctx *ctx)
+{
+#if __LINUX_ARM_ARCH__ < 7
+ emit(ARM_LDR_I(rd, ARM_PC, imm_offset(val, ctx)), ctx);
+#else
+ emit(ARM_MOVW(rd, val & 0xffff), ctx);
+ if (val > 0xffff)
+ emit(ARM_MOVT(rd, val >> 16), ctx);
+#endif
+}
+
+static inline void emit_mov_i(int rd, u32 val, struct jit_ctx *ctx)
+{
+ int imm12 = imm8m(val);
+
+ if (imm12 >= 0)
+ emit(ARM_MOV_I(rd, imm12), ctx);
+ else
+ emit_mov_i_no8m(rd, val, ctx);
+}
+
+#if __LINUX_ARM_ARCH__ < 6
+
+static void emit_load_be32(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
+{
+ _emit(cond, ARM_LDRB_I(ARM_R3, r_addr, 1), ctx);
+ _emit(cond, ARM_LDRB_I(ARM_R1, r_addr, 0), ctx);
+ _emit(cond, ARM_LDRB_I(ARM_R2, r_addr, 3), ctx);
+ _emit(cond, ARM_LSL_I(ARM_R3, ARM_R3, 16), ctx);
+ _emit(cond, ARM_LDRB_I(ARM_R0, r_addr, 2), ctx);
+ _emit(cond, ARM_ORR_S(ARM_R3, ARM_R3, ARM_R1, SRTYPE_LSL, 24), ctx);
+ _emit(cond, ARM_ORR_R(ARM_R3, ARM_R3, ARM_R2), ctx);
+ _emit(cond, ARM_ORR_S(r_res, ARM_R3, ARM_R0, SRTYPE_LSL, 8), ctx);
+}
+
+static void emit_load_be16(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
+{
+ _emit(cond, ARM_LDRB_I(ARM_R1, r_addr, 0), ctx);
+ _emit(cond, ARM_LDRB_I(ARM_R2, r_addr, 1), ctx);
+ _emit(cond, ARM_ORR_S(r_res, ARM_R2, ARM_R1, SRTYPE_LSL, 8), ctx);
+}
+
+static inline void emit_swap16(u8 r_dst, u8 r_src, struct jit_ctx *ctx)
+{
+ emit(ARM_LSL_R(ARM_R1, r_src, 8), ctx);
+ emit(ARM_ORR_S(r_dst, ARM_R1, r_src, SRTYPE_LSL, 8), ctx);
+ emit(ARM_LSL_I(r_dst, r_dst, 8), ctx);
+ emit(ARM_LSL_R(r_dst, r_dst, 8), ctx);
+}
+
+#else /* ARMv6+ */
+
+static void emit_load_be32(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
+{
+ _emit(cond, ARM_LDR_I(r_res, r_addr, 0), ctx);
+#ifdef __LITTLE_ENDIAN
+ _emit(cond, ARM_REV(r_res, r_res), ctx);
+#endif
+}
+
+static void emit_load_be16(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
+{
+ _emit(cond, ARM_LDRH_I(r_res, r_addr, 0), ctx);
+#ifdef __LITTLE_ENDIAN
+ _emit(cond, ARM_REV16(r_res, r_res), ctx);
+#endif
+}
+
+static inline void emit_swap16(u8 r_dst __maybe_unused,
+ u8 r_src __maybe_unused,
+ struct jit_ctx *ctx __maybe_unused)
+{
+#ifdef __LITTLE_ENDIAN
+ emit(ARM_REV16(r_dst, r_src), ctx);
+#endif
+}
+
+#endif /* __LINUX_ARM_ARCH__ < 6 */
+
+
+/* Compute the immediate value for a PC-relative branch. */
+static inline u32 b_imm(unsigned tgt, struct jit_ctx *ctx)
+{
+ u32 imm;
+
+ if (ctx->target == NULL)
+ return 0;
+ /*
+ * BPF allows only forward jumps and the offset of the target is
+ * still the one computed during the first pass.
+ */
+ imm = ctx->offsets[tgt] + ctx->prologue_bytes - (ctx->idx * 4 + 8);
+
+ return imm >> 2;
+}
+
+#define OP_IMM3(op, r1, r2, imm_val, ctx) \
+ do { \
+ imm12 = imm8m(imm_val); \
+ if (imm12 < 0) { \
+ emit_mov_i_no8m(r_scratch, imm_val, ctx); \
+ emit(op ## _R((r1), (r2), r_scratch), ctx); \
+ } else { \
+ emit(op ## _I((r1), (r2), imm12), ctx); \
+ } \
+ } while (0)
+
+static inline void emit_err_ret(u8 cond, struct jit_ctx *ctx)
+{
+ if (ctx->ret0_fp_idx >= 0) {
+ _emit(cond, ARM_B(b_imm(ctx->ret0_fp_idx, ctx)), ctx);
+ /* NOP to keep the size constant between passes */
+ emit(ARM_MOV_R(ARM_R0, ARM_R0), ctx);
+ } else {
+ _emit(cond, ARM_MOV_I(ARM_R0, 0), ctx);
+ _emit(cond, ARM_B(b_imm(ctx->skf->len, ctx)), ctx);
+ }
+}
+
+static inline void emit_blx_r(u8 tgt_reg, struct jit_ctx *ctx)
+{
+#if __LINUX_ARM_ARCH__ < 5
+ emit(ARM_MOV_R(ARM_LR, ARM_PC), ctx);
+
+ if (elf_hwcap & HWCAP_THUMB)
+ emit(ARM_BX(tgt_reg), ctx);
+ else
+ emit(ARM_MOV_R(ARM_PC, tgt_reg), ctx);
+#else
+ emit(ARM_BLX_R(tgt_reg), ctx);
+#endif
+}
+
+static inline void emit_udiv(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx)
+{
+#if __LINUX_ARM_ARCH__ == 7
+ if (elf_hwcap & HWCAP_IDIVA) {
+ emit(ARM_UDIV(rd, rm, rn), ctx);
+ return;
+ }
+#endif
+ if (rm != ARM_R0)
+ emit(ARM_MOV_R(ARM_R0, rm), ctx);
+ if (rn != ARM_R1)
+ emit(ARM_MOV_R(ARM_R1, rn), ctx);
+
+ ctx->seen |= SEEN_CALL;
+ emit_mov_i(ARM_R3, (u32)jit_udiv, ctx);
+ emit_blx_r(ARM_R3, ctx);
+
+ if (rd != ARM_R0)
+ emit(ARM_MOV_R(rd, ARM_R0), ctx);
+}
+
+static int build_body(struct jit_ctx *ctx)
+{
+ void *load_func[] = {jit_get_skb_b, jit_get_skb_h, jit_get_skb_w};
+ const struct sk_filter *prog = ctx->skf;
+ const struct sock_filter *inst;
+ unsigned i, load_order, off, condt, condf;
+ int imm12;
+ u32 k;
+
+ for (i = 0; i < prog->len; i++) {
+ inst = &(prog->insns[i]);
+ /* K as an immediate value operand */
+ k = inst->k;
+
+ /* compute offsets only in the fake pass */
+ if (ctx->target == NULL)
+ ctx->offsets[i] = ctx->idx * 4;
+
+ switch (inst->code) {
+ case BPF_S_LD_IMM:
+ emit_mov_i(r_A, k, ctx);
+ break;
+ case BPF_S_LD_W_LEN:
+ ctx->seen |= SEEN_LEN;
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
+ emit(ARM_LDR_I(r_A, r_skb,
+ offsetof(struct sk_buff, len)), ctx);
+ break;
+ case BPF_S_LD_MEM:
+ /* A = scratch[k] */
+ ctx->seen |= SEEN_MEM_WORD(k);
+ emit(ARM_LDR_I(r_A, ARM_SP, SCRATCH_OFF(k)), ctx);
+ break;
+ case BPF_S_LD_W_ABS:
+ load_order = 2;
+ goto load;
+ case BPF_S_LD_H_ABS:
+ load_order = 1;
+ goto load;
+ case BPF_S_LD_B_ABS:
+ load_order = 0;
+load:
+ emit_mov_i(r_off, k, ctx);
+load_common:
+ ctx->seen |= SEEN_DATA | SEEN_CALL;
+
+ if (load_order > 0) {
+ emit(ARM_SUB_I(r_scratch, r_skb_hl,
+ 1 << load_order), ctx);
+ emit(ARM_CMP_R(r_scratch, r_off), ctx);
+ condt = ARM_COND_HS;
+ } else {
+ emit(ARM_CMP_R(r_skb_hl, r_off), ctx);
+ condt = ARM_COND_HI;
+ }
+
+ _emit(condt, ARM_ADD_R(r_scratch, r_off, r_skb_data),
+ ctx);
+
+ if (load_order == 0)
+ _emit(condt, ARM_LDRB_I(r_A, r_scratch, 0),
+ ctx);
+ else if (load_order == 1)
+ emit_load_be16(condt, r_A, r_scratch, ctx);
+ else if (load_order == 2)
+ emit_load_be32(condt, r_A, r_scratch, ctx);
+
+ _emit(condt, ARM_B(b_imm(i + 1, ctx)), ctx);
+
+ /* the slowpath */
+ emit_mov_i(ARM_R3, (u32)load_func[load_order], ctx);
+ emit(ARM_MOV_R(ARM_R0, r_skb), ctx);
+ /* the offset is already in R1 */
+ emit_blx_r(ARM_R3, ctx);
+ emit(ARM_MOV_R(r_A, ARM_R0), ctx);
+ break;
+ case BPF_S_LD_W_IND:
+ load_order = 2;
+ goto load_ind;
+ case BPF_S_LD_H_IND:
+ load_order = 1;
+ goto load_ind;
+ case BPF_S_LD_B_IND:
+ load_order = 0;
+load_ind:
+ OP_IMM3(ARM_ADD, r_off, r_X, k, ctx);
+ goto load_common;
+ case BPF_S_LDX_IMM:
+ ctx->seen |= SEEN_X;
+ emit_mov_i(r_X, k, ctx);
+ break;
+ case BPF_S_LDX_W_LEN:
+ ctx->seen |= SEEN_X;
+ emit(ARM_LDR_I(r_X, r_skb,
+ offsetof(struct sk_buff, len)), ctx);
+ break;
+ case BPF_S_LDX_MEM:
+ ctx->seen |= SEEN_X | SEEN_MEM_WORD(k);
+ emit(ARM_LDR_I(r_X, ARM_SP, SCRATCH_OFF(k)), ctx);
+ break;
+ case BPF_S_LDX_B_MSH:
+ /* x = ((*(frame + k)) & 0xf) << 2; */
+ ctx->seen |= SEEN_X | SEEN_DATA | SEEN_CALL;
+ /* offset in r1: we might have to take the slow path */
+ emit_mov_i(r_off, k, ctx);
+ emit(ARM_CMP_R(r_skb_hl, r_off), ctx);
+
+ /* load in r0: common with the slowpath */
+ _emit(ARM_COND_HI, ARM_LDRB_R(ARM_R0, r_skb_data,
+ ARM_R1), ctx);
+ _emit(ARM_COND_HI, ARM_B((3 * 4 - 8) >> 2), ctx);
+
+ emit(ARM_MOV_R(ARM_R0, r_skb), ctx);
+ /* r_off is r1 */
+ emit(ARM_MOV_I(ARM_R3, (u32)jit_get_skb_b), ctx);
+ emit_blx_r(ARM_R3, ctx);
+
+ emit(ARM_ORR_I(r_X, ARM_R0, 0x00f), ctx);
+ emit(ARM_LSL_I(r_X, r_X, 2), ctx);
+ break;
+ case BPF_S_ST:
+ ctx->seen |= SEEN_MEM_WORD(k);
+ emit(ARM_STR_I(r_A, ARM_SP, SCRATCH_OFF(k)), ctx);
+ break;
+ case BPF_S_STX:
+ ctx->seen |= SEEN_MEM_WORD(k) | SEEN_X;
+ emit(ARM_STR_I(r_X, ARM_SP, SCRATCH_OFF(k)), ctx);
+ break;
+ case BPF_S_ALU_ADD_K:
+ /* A += K */
+ OP_IMM3(ARM_ADD, r_A, r_A, k, ctx);
+ break;
+ case BPF_S_ALU_ADD_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_ADD_R(r_A, r_A, r_X), ctx);
+ break;
+ case BPF_S_ALU_SUB_K:
+ /* A -= K */
+ OP_IMM3(ARM_SUB, r_A, r_A, k, ctx);
+ break;
+ case BPF_S_ALU_SUB_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_SUB_R(r_A, r_A, r_X), ctx);
+ break;
+ case BPF_S_ALU_MUL_K:
+ /* A *= K */
+ emit_mov_i(r_scratch, k, ctx);
+ emit(ARM_MUL(r_A, r_A, r_scratch), ctx);
+ break;
+ case BPF_S_ALU_MUL_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_MUL(r_A, r_A, r_X), ctx);
+ break;
+ case BPF_S_ALU_DIV_K:
+ /* current k == reciprocal_value(userspace k) */
+ emit_mov_i(r_scratch, k, ctx);
+ /* A = top 32 bits of the product */
+ emit(ARM_UMULL(r_scratch, r_A, r_A, r_scratch), ctx);
+ break;
+ case BPF_S_ALU_DIV_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_CMP_I(r_X, 0), ctx);
+ emit_err_ret(ARM_COND_EQ, ctx);
+ emit_udiv(r_A, r_A, r_X, ctx);
+ break;
+ case BPF_S_ALU_OR_K:
+ /* A |= K */
+ OP_IMM3(ARM_ORR, r_A, r_A, k, ctx);
+ break;
+ case BPF_S_ALU_OR_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_ORR_I(r_A, r_A, r_X), ctx);
+ break;
+ case BPF_S_ALU_AND_K:
+ /* A &= K */
+ OP_IMM3(ARM_AND, r_A, r_A, k, ctx);
+ break;
+ case BPF_S_ALU_AND_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_AND_R(r_A, r_A, r_X), ctx);
+ break;
+ case BPF_S_ALU_LSH_K:
+ if (unlikely(k > 31))
+ return -1;
+ emit(ARM_LSL_I(r_A, r_A, k), ctx);
+ break;
+ case BPF_S_ALU_LSH_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_LSL_R(r_A, r_A, r_X), ctx);
+ break;
+ case BPF_S_ALU_RSH_K:
+ if (unlikely(k > 31))
+ return -1;
+ emit(ARM_LSR_I(r_A, r_A, k), ctx);
+ break;
+ case BPF_S_ALU_RSH_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_LSR_R(r_A, r_A, r_X), ctx);
+ break;
+ case BPF_S_JMP_JA:
+ /* pc += K */
+ emit(ARM_B(b_imm(i + k, ctx)), ctx);
+ break;
+ case BPF_S_JMP_JEQ_K:
+ /* pc += (A == K) ? pc->jt : pc->jf */
+ condt = ARM_COND_EQ;
+ condf = ARM_COND_NE;
+ goto cmp_imm;
+ case BPF_S_JMP_JGT_K:
+ /* pc += (A > K) ? pc->jt : pc->jf */
+ condt = ARM_COND_HI;
+ condf = ARM_COND_LS;
+ goto cmp_imm;
+ case BPF_S_JMP_JGE_K:
+ /* pc += (A >= K) ? pc->jt : pc->jf */
+ condt = ARM_COND_HI;
+ condf = ARM_COND_LS;
+ /* (x >= y) IFF (x > y - 1) */
+ if (unlikely(k == 0))
+ return -1;
+ k--;
+cmp_imm:
+ imm12 = imm8m(k);
+ if (imm12 < 0) {
+ emit_mov_i_no8m(r_scratch, k, ctx);
+ emit(ARM_CMP_R(r_A, r_scratch), ctx);
+ } else {
+ emit(ARM_CMP_I(r_A, imm12), ctx);
+ }
+cond_jump:
+ if (inst->jt)
+ _emit(condt, ARM_B(b_imm(i + inst->jt + 1,
+ ctx)), ctx);
+ if (inst->jf)
+ _emit(condf, ARM_B(b_imm(i + inst->jf + 1,
+ ctx)), ctx);
+ break;
+ case BPF_S_JMP_JEQ_X:
+ /* pc += (A == X) ? pc->jt : pc->jf */
+ condt = ARM_COND_EQ;
+ condf = ARM_COND_NE;
+ goto cmp_x;
+ case BPF_S_JMP_JGT_X:
+ /* pc += (A > X) ? pc->jt : pc->jf */
+ condt = ARM_COND_HI;
+ condf = ARM_COND_LS;
+ goto cmp_x;
+ case BPF_S_JMP_JGE_X:
+ /* pc += (A >= X) ? pc->jt : pc->jf */
+ condt = ARM_COND_CS;
+ condf = ARM_COND_CC;
+cmp_x:
+ ctx->seen |= SEEN_X;
+ emit(ARM_CMP_R(r_A, r_X), ctx);
+ goto cond_jump;
+ case BPF_S_JMP_JSET_K:
+ /* pc += (A & K) ? pc->jt : pc->jf */
+ condt = ARM_COND_NE;
+ /* not set iff all zeroes iff Z==1 iff EQ */
+ condf = ARM_COND_EQ;
+
+ imm12 = imm8m(k);
+ if (imm12 < 0) {
+ emit_mov_i_no8m(r_scratch, k, ctx);
+ emit(ARM_TST_R(r_A, r_scratch), ctx);
+ } else {
+ emit(ARM_TST_I(r_A, imm12), ctx);
+ }
+ goto cond_jump;
+ case BPF_S_JMP_JSET_X:
+ /* pc += (A & X) ? pc->jt : pc->jf */
+ condt = ARM_COND_NE;
+ condf = ARM_COND_EQ;
+ emit(ARM_TST_R(r_A, r_X), ctx);
+ goto cond_jump;
+ case BPF_S_RET_A:
+ emit(ARM_MOV_R(ARM_R0, r_A), ctx);
+ goto b_epilogue;
+ case BPF_S_RET_K:
+ if ((k == 0) && (ctx->ret0_fp_idx < 0))
+ ctx->ret0_fp_idx = i;
+ emit_mov_i(ARM_R0, k, ctx);
+b_epilogue:
+ if (i != ctx->skf->len - 1)
+ emit(ARM_B(b_imm(prog->len, ctx)), ctx);
+ break;
+ case BPF_S_MISC_TAX:
+ /* X = A */
+ emit(ARM_MOV_R(r_X, r_A), ctx);
+ break;
+ case BPF_S_MISC_TXA:
+ /* A = X */
+ emit(ARM_MOV_R(r_A, r_X), ctx);
+ break;
+ case BPF_S_ANC_PROTOCOL:
+ /* A = ntohs(skb->protocol) */
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
+ protocol) != 2);
+ off = offsetof(struct sk_buff, protocol);
+ emit(ARM_LDRH_I(r_scratch, r_skb, off), ctx);
+ emit_swap16(r_A, r_scratch, ctx);
+ break;
+ case BPF_S_ANC_CPU:
+ /* A = current_thread_info()->cpu */
+ emit_mov_i(r_scratch, (~(THREAD_SIZE - 1)), ctx);
+ emit(ARM_ADD_R(r_scratch, ARM_SP, r_scratch), ctx);
+
+ BUILD_BUG_ON(FIELD_SIZEOF(struct thread_info, cpu) != 4);
+ off = offsetof(struct thread_info, cpu);
+ emit(ARM_LDR_I(r_A, r_scratch, off), ctx);
+ break;
+ case BPF_S_ANC_IFINDEX:
+ /* A = skb->dev->ifindex */
+ off = offsetof(struct sk_buff, dev);
+ emit(ARM_LDR_I(r_scratch, r_skb, off), ctx);
+
+ emit(ARM_CMP_I(r_scratch, 0), ctx);
+ emit_err_ret(ARM_COND_EQ, ctx);
+
+ BUILD_BUG_ON(FIELD_SIZEOF(struct net_device,
+ ifindex) != 4);
+ off = offsetof(struct net_device, ifindex);
+ emit(ARM_LDR_I(r_A, r_scratch, off), ctx);
+ break;
+ case BPF_S_ANC_MARK:
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
+ off = offsetof(struct sk_buff, mark);
+ emit(ARM_LDR_I(r_A, r_skb, off), ctx);
+ break;
+ case BPF_S_ANC_RXHASH:
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
+ off = offsetof(struct sk_buff, rxhash);
+ emit(ARM_LDR_I(r_A, r_skb, off), ctx);
+ break;
+ case BPF_S_ANC_QUEUE:
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
+ queue_mapping) != 2);
+ BUILD_BUG_ON(offsetof(struct sk_buff,
+ queue_mapping) > 0xff);
+ off = offsetof(struct sk_buff, queue_mapping);
+ emit(ARM_LDRH_I(r_A, r_skb, off), ctx);
+ break;
+ default:
+ return -1;
+ }
+ }
+
+ /* compute offsets only during the first pass */
+ if (ctx->target == NULL)
+ ctx->offsets[i] = ctx->idx * 4;
+
+ return 0;
+}
+
+
+void bpf_jit_compile(struct sk_filter *fp)
+{
+ struct jit_ctx ctx;
+ unsigned tmp_idx;
+ unsigned alloc_size;
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.skf = fp;
+ ctx.ret0_fp_idx = -1;
+
+ ctx.offsets = kzalloc(GFP_KERNEL, 4 * (ctx.skf->len + 1));
+ if (ctx.offsets == NULL)
+ return;
+
+ /* fake pass to fill in the ctx->seen */
+ if (unlikely(build_body(&ctx)))
+ goto out;
+
+ tmp_idx = ctx.idx;
+ build_prologue(&ctx);
+ ctx.prologue_bytes = (ctx.idx - tmp_idx) * 4;
+
+#if __LINUX_ARM_ARCH__ < 7
+ tmp_idx = ctx.idx;
+ build_epilogue(&ctx);
+ ctx.epilogue_bytes = (ctx.idx - tmp_idx) * 4;
+
+ ctx.idx += ctx.imm_count;
+ if (ctx.imm_count) {
+ ctx.imms = kzalloc(GFP_KERNEL, 4 * ctx.imm_count);
+ if (ctx.imms == NULL)
+ goto out;
+ }
+#else
+ /* there's nothing after the epilogue on ARMv7 */
+ build_epilogue(&ctx);
+#endif
+
+ alloc_size = 4 * ctx.idx;
+ ctx.target = module_alloc(alloc_size > sizeof(struct work_struct) ?
+ alloc_size : sizeof(struct work_struct));
+ if (unlikely(ctx.target == NULL))
+ goto out;
+
+ ctx.idx = 0;
+ build_prologue(&ctx);
+ build_body(&ctx);
+ build_epilogue(&ctx);
+
+ flush_icache_range((u32)ctx.target, (u32)(ctx.target + ctx.idx));
+
+#if __LINUX_ARM_ARCH__ < 7
+ if (ctx.imm_count)
+ kfree(ctx.imms);
+#endif
+
+ if (bpf_jit_enable > 1)
+ print_hex_dump(KERN_INFO, "BPF JIT code: ",
+ DUMP_PREFIX_ADDRESS, 16, 4, ctx.target,
+ alloc_size, false);
+
+ fp->bpf_func = (void *)ctx.target;
+out:
+ kfree(ctx.offsets);
+ return;
+}
+
+static void bpf_jit_free_worker(struct work_struct *work)
+{
+ module_free(NULL, work);
+}
+
+void bpf_jit_free(struct sk_filter *fp)
+{
+ struct work_struct *work;
+
+ if (fp->bpf_func != sk_run_filter) {
+ work = (struct work_struct *)fp->bpf_func;
+
+ INIT_WORK(work, bpf_jit_free_worker);
+ schedule_work(work);
+ }
+}
+
diff --git a/arch/arm/net/bpf_jit_32.h b/arch/arm/net/bpf_jit_32.h
new file mode 100644
index 0000000..d55f3f3
--- /dev/null
+++ b/arch/arm/net/bpf_jit_32.h
@@ -0,0 +1,180 @@
+/*
+ * Just-In-Time compiler for BPF filters on 32bit ARM
+ *
+ * Copyright (c) 2011 Mircea Gherzan <mgherzan@gmail.com>
+ *
+ * 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; version 2 of the License.
+ */
+
+#ifndef PFILTER_OPCODES_ARM_H
+#define PFILTER_OPCODES_ARM_H
+
+#define ARM_R0 0
+#define ARM_R1 1
+#define ARM_R2 2
+#define ARM_R3 3
+#define ARM_R4 4
+#define ARM_R5 5
+#define ARM_R6 6
+#define ARM_R7 7
+#define ARM_R8 8
+#define ARM_R9 9
+#define ARM_R10 10
+#define ARM_FP 11
+#define ARM_IP 12
+#define ARM_SP 13
+#define ARM_LR 14
+#define ARM_PC 15
+
+#define ARM_COND_EQ 0x0
+#define ARM_COND_NE 0x1
+#define ARM_COND_CS 0x2
+#define ARM_COND_HS ARM_COND_CS
+#define ARM_COND_CC 0x3
+#define ARM_COND_LO ARM_COND_CC
+#define ARM_COND_MI 0x4
+#define ARM_COND_PL 0x5
+#define ARM_COND_VS 0x6
+#define ARM_COND_VC 0x7
+#define ARM_COND_HI 0x8
+#define ARM_COND_LS 0x9
+#define ARM_COND_GE 0xa
+#define ARM_COND_LT 0xb
+#define ARM_COND_GT 0xc
+#define ARM_COND_LE 0xd
+#define ARM_COND_AL 0xe
+
+/* register shift types */
+#define SRTYPE_LSL 0
+#define SRTYPE_LSR 1
+#define SRTYPE_ASR 2
+#define SRTYPE_ROR 3
+
+#define ARM_INST_ADD_R 0x00800000
+#define ARM_INST_ADD_I 0x02800000
+
+#define ARM_INST_AND_R 0x00000000
+#define ARM_INST_AND_I 0x02000000
+
+#define ARM_INST_B 0x0a000000
+#define ARM_INST_BX 0x012FFF10
+#define ARM_INST_BLX_R 0x012fff30
+
+#define ARM_INST_CMP_R 0x01500000
+#define ARM_INST_CMP_I 0x03500000
+
+#define ARM_INST_LDRB_I 0x05d00000
+#define ARM_INST_LDRB_R 0x07d00000
+#define ARM_INST_LDRH_I 0x01d000b0
+#define ARM_INST_LDR_I 0x05900000
+
+#define ARM_INST_LDM 0x08900000
+
+#define ARM_INST_LSL_I 0x01a00000
+#define ARM_INST_LSL_R 0x01a00010
+
+#define ARM_INST_LSR_I 0x01a00020
+#define ARM_INST_LSR_R 0x01a00030
+
+#define ARM_INST_MOV_R 0x01a00000
+#define ARM_INST_MOV_I 0x03a00000
+#define ARM_INST_MOVW 0x03000000
+#define ARM_INST_MOVT 0x03400000
+
+#define ARM_INST_MUL 0x00000090
+
+#define ARM_INST_POP 0x08bd0000
+#define ARM_INST_PUSH 0x092d0000
+
+#define ARM_INST_REV 0x06bf0f30
+#define ARM_INST_REV16 0x06bf0fb0
+
+#define ARM_INST_ORR_R 0x01800000
+#define ARM_INST_ORR_I 0x03800000
+
+#define ARM_INST_SUB_R 0x00400000
+#define ARM_INST_SUB_I 0x02400000
+
+#define ARM_INST_STR_I 0x05800000
+
+#define ARM_INST_TST_R 0x01100000
+#define ARM_INST_TST_I 0x03100000
+
+#define ARM_INST_UDIV 0x0730f010
+
+#define ARM_INST_UMULL 0x00800090
+
+/* register */
+#define _AL3_R(op, rd, rn, rm) ((op ## _R) | (rd) << 12 | (rn) << 16 | (rm))
+/* immediate */
+#define _AL3_I(op, rd, rn, imm) ((op ## _I) | (rd) << 12 | (rn) << 16 | (imm))
+
+#define ARM_ADD_R(rd, rn, rm) _AL3_R(ARM_INST_ADD, rd, rn, rm)
+#define ARM_ADD_I(rd, rn, imm) _AL3_I(ARM_INST_ADD, rd, rn, imm)
+
+#define ARM_AND_R(rd, rn, rm) _AL3_R(ARM_INST_AND, rd, rn, rm)
+#define ARM_AND_I(rd, rn, imm) _AL3_I(ARM_INST_AND, rd, rn, imm)
+
+#define ARM_B(imm24) (ARM_INST_B | (imm24))
+#define ARM_BX(rm) (ARM_INST_BX | (rm))
+#define ARM_BLX_R(rm) (ARM_INST_BLX_R | (rm))
+
+#define ARM_CMP_R(rn, rm) _AL3_R(ARM_INST_CMP, 0, rn, rm)
+#define ARM_CMP_I(rn, imm) _AL3_I(ARM_INST_CMP, 0, rn, imm)
+
+#define ARM_LDR_I(rt, rn, off) (ARM_INST_LDR_I | (rt) << 12 | (rn) << 16 \
+ | (off))
+#define ARM_LDRB_I(rt, rn, off) (ARM_INST_LDRB_I | (rt) << 12 | (rn) << 16 \
+ | (off))
+#define ARM_LDRB_R(rt, rn, rm) (ARM_INST_LDRB_R | (rt) << 12 | (rn) << 16 \
+ | (rm))
+#define ARM_LDRH_I(rt, rn, off) (ARM_INST_LDRH_I | (rt) << 12 | (rn) << 16 \
+ | (((off) & 0xf0) << 4) | ((off) & 0xf))
+
+#define ARM_LDM(rn, regs) (ARM_INST_LDM | (rn) << 16 | (regs))
+
+#define ARM_LSL_R(rd, rn, rm) (_AL3_R(ARM_INST_LSL, rd, 0, rn) | (rm) << 8)
+#define ARM_LSL_I(rd, rn, imm) (_AL3_R(ARM_INST_LSL, rd, 0, rn) | (imm) << 7)
+
+#define ARM_LSR_R(rd, rn, rm) (_AL3_R(ARM_INST_LSR, rd, 0, rn) | (rm) << 8)
+#define ARM_LSR_I(rd, rn, imm) (_AL3_R(ARM_INST_LSR, rd, 0, rn) | (imm) << 7)
+
+#define ARM_MOV_R(rd, rm) _AL3_R(ARM_INST_MOV, rd, 0, rm)
+#define ARM_MOV_I(rd, imm) _AL3_I(ARM_INST_MOV, rd, 0, imm)
+
+#define ARM_MOVW(rd, imm) \
+ (ARM_INST_MOVW | ((imm) >> 12) << 16 | (rd) << 12 | ((imm) & 0x0fff))
+
+#define ARM_MOVT(rd, imm) \
+ (ARM_INST_MOVT | ((imm) >> 12) << 16 | (rd) << 12 | ((imm) & 0x0fff))
+
+#define ARM_MUL(rd, rm, rn) (ARM_INST_MUL | (rd) << 16 | (rm) << 8 | (rn))
+
+#define ARM_POP(regs) (ARM_INST_POP | (regs))
+#define ARM_PUSH(regs) (ARM_INST_PUSH | (regs))
+
+#define ARM_ORR_R(rd, rn, rm) _AL3_R(ARM_INST_ORR, rd, rn, rm)
+#define ARM_ORR_I(rd, rn, imm) _AL3_I(ARM_INST_ORR, rd, rn, imm)
+#define ARM_ORR_S(rd, rn, rm, type, rs) \
+ (ARM_ORR_R(rd, rn, rm) | (type) << 5 | (rs) << 7)
+
+#define ARM_REV(rd, rm) (ARM_INST_REV | (rd) << 12 | (rm))
+#define ARM_REV16(rd, rm) (ARM_INST_REV16 | (rd) << 12 | (rm))
+
+#define ARM_SUB_R(rd, rn, rm) _AL3_R(ARM_INST_SUB, rd, rn, rm)
+#define ARM_SUB_I(rd, rn, imm) _AL3_I(ARM_INST_SUB, rd, rn, imm)
+
+#define ARM_STR_I(rt, rn, off) (ARM_INST_STR_I | (rt) << 12 | (rn) << 16 \
+ | (off))
+
+#define ARM_TST_R(rn, rm) _AL3_R(ARM_INST_TST, 0, rn, rm)
+#define ARM_TST_I(rn, imm) _AL3_I(ARM_INST_TST, 0, rn, imm)
+
+#define ARM_UDIV(rd, rn, rm) (ARM_INST_UDIV | (rd) << 16 | (rn) | (rm) << 8)
+
+#define ARM_UMULL(rd_lo, rd_hi, rn, rm) (ARM_INST_UMULL | (rd_hi) << 16 \
+ | (rd_lo) << 12 | (rm) << 8 | rn)
+
+#endif /* PFILTER_OPCODES_ARM_H */
--
1.7.7.3
^ permalink raw reply related
* Re: [PATCH] bridge: push blocking slaves to forwarding when turning stp off
From: Stephen Hemminger @ 2011-12-20 18:11 UTC (permalink / raw)
To: Vitalii Demianets; +Cc: netdev, bridge, Michael Tremer
In-Reply-To: <201112201259.12086.vitas@nppfactor.kiev.ua>
On Tue, 20 Dec 2011 12:59:11 +0200
Vitalii Demianets <vitas@nppfactor.kiev.ua> wrote:
> Hello, Stephen!
> I can not understand your silence.
> There are issues fixed by the patch in question. For example, if the interface
> is left in blocking state after stp was turned off, that state is not
> stable - it can flip to forwarding state in unpredictable times, e.g. when
> _any other_ slave of the bridge goes up or down. Do you think user wants
> exactly that unpredictable state change?
> Also, the code in question in function br_stp_stop(), namely
> br_port_state_selection(br) call, does exactly nothing except wasting cpu
> cycles. Isn't it worth fixing?
>
I had to go do real work last week.
Let me test and look at it more detail.
There is no urgency, the problem has existed for many years.
^ permalink raw reply
* RE: [PATCH 0/2] Tracepoint for tcp retransmission
From: Satoru Moriya @ 2011-12-20 18:13 UTC (permalink / raw)
To: Stephen Hemminger
Cc: nhorman@tuxdriver.com, davem@davemloft.net, tgraf@infradead.org,
Seiji Aguchi, dle-develop@lists.sourceforge.net,
netdev@vger.kernel.org
In-Reply-To: <5f654c7d-f18e-4d70-8830-a3e31b8f5f4a@tahiti.vyatta.com>
On 12/16/2011 07:17 PM, Stephen Hemminger wrote:
>
>> Sometimes network packets are dropped for some reason. In enterprise
>> systems which require strict RAS functionality, we must know the
>> reason why it happened and explain it to our customers even if using
>> TCP. When we investigate the incidents, at first we try to find out
>> whether the problem is in the server(kernel, application) or else
>> (router, hub etc). And next we try to find out which layer
>> (application/middleware/kernel(IP/TCP/UDP/..)etc.) the problem
>> occurs.
>
> I feel sorry for you, your users don't understand TCP. TCP
> intentionally induces loss to measure capacity. This is one of the
> fundamental principles of loss based congestion control.
Maybe my explanation was not enough, I think...
Yes, as you said above, TCP induces loss in principle. Actually,
customers doesn't think that is a problem. But, at the same time
packet drop occurs everywhere in network due to BUG, wrong
configuration, broken hardware and/or etc. and sometimes it
causes serious problems to customers' system.
We provide Linux support service in our business and when a
serious problem occurs, we collect and analyze logs and find
where the problem is.
With this tracepoint, we're able to know whether the problem
is in OS or somewhere else. (Negative return value means packet
drop happened inside OS.)
That's a great help for us narrow down the root cause of
the problem.
I'll rewrite the cover letter when I post v2.
Regards,
Satoru
^ permalink raw reply
* Re: [PATCH] bridge: push blocking slaves to forwarding when turning stp off
From: Vitalii Demianets @ 2011-12-20 18:27 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev, bridge
In-Reply-To: <20111220101117.2a3eb12f@nehalam.linuxnetplumber.net>
On Tuesday 20 December 2011 20:11:17 Stephen Hemminger wrote:
> I had to go do real work last week.
> Let me test and look at it more detail.
> There is no urgency, the problem has existed for many years.
Please excuse me. It was only my impatience and "deferred" status on the
David's patchwork site that worried me.
I agree that problem is not urgent.
--
Vitalii Demianets
^ permalink raw reply
* Re: [PATCH] batman-adv: checkpatch cleanup - remove lines longer than 80 chars
From: David Miller @ 2011-12-20 18:32 UTC (permalink / raw)
To: lindner_marek-LWAfsSFWpa4
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r
In-Reply-To: <1324377504-20983-1-git-send-email-lindner_marek-LWAfsSFWpa4@public.gmane.org>
From: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
Date: Tue, 20 Dec 2011 18:38:24 +0800
> The long line was introduced with b26e478f8f.
>
> Signed-off-by: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
I'm not applying this.
I tell people to make sure arguments line up correctly to the
openning parenthesis on the previous line, and that is what is
happening here.
^ permalink raw reply
* Re: linux-3.0.x regression with ipv4 routes having mtu
From: David Miller @ 2011-12-20 18:35 UTC (permalink / raw)
To: steffen.klassert; +Cc: timo.teras, netdev
In-Reply-To: <20111220071843.GL6348@secunet.com>
From: Steffen Klassert <steffen.klassert@secunet.com>
Date: Tue, 20 Dec 2011 08:18:43 +0100
> On Tue, Dec 20, 2011 at 02:03:55AM -0500, David Miller wrote:
>> From: Timo Teräs <timo.teras@iki.fi>
>> Date: Tue, 20 Dec 2011 08:53:09 +0200
>>
>> > Or maybe I missed the place where that updated would happen?
>>
>> It should happen on every routing cache lookup hit just like we
>> validate the peer for redirect information.
>
> The problem is that we need to do a route cache lookup to
> validate the peer informations. This does not happen if
> somebody adds a new route. I tried already to add a pmtu specific
> generation id and it appears to not solve the problem. We would
> still need to overwrite the cached value if we add a route with mtu.
Why?
Every use of a routing cache entry does a dst_check() or a routing
cache lookup.
You can check the generation ID in both locations, and if the
comparison fails then you force the routing cache entry to be killed
and the caller performs a lookup. At that time the refreshing of the
new FIB entry will be realized.
The critical bit is invalidating the routing cache entry, I can only
guess that you're not doing that.
^ permalink raw reply
* Re: [PATCH] stmmac: reduce queue lengths if MTU is very large
From: David Miller @ 2011-12-20 18:41 UTC (permalink / raw)
To: rubini; +Cc: peppe.cavallaro, netdev, giancarlo.asnaghi
In-Reply-To: <20111220073050.GA2817@mail.gnudd.com>
From: Alessandro Rubini <rubini@gnudd.com>
Date: Tue, 20 Dec 2011 08:30:50 +0100
> Allocation of the queues is based on a parameter. If the parameter was
> a size, instead of a lenght, all would be fine, wouldn't it? If you
> agree, then this patch is turning the lenght into a size, in a way.
That doesn't make any sense either, queues are sized by TX descriptor
slots not bytes.
> Now, how could we deal with the fact that the size explodes if the MTU
> is increased?
Maybe... set the initial parameter appropriately? This is enormously
better than fixing it up after the fact.
Maybe I set the number of TX entries based upon my expected packet
load of small packets. If I happen to set my MTU to 9000 that's
irrelevant to the setting.
^ permalink raw reply
* Re: [PATCH net-next] mlx4_en: FIX: Setting default_qpn before using it
From: David Miller @ 2011-12-20 18:44 UTC (permalink / raw)
To: yevgenyp; +Cc: netdev
In-Reply-To: <4EF03F02.4010904@mellanox.co.il>
From: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
Date: Tue, 20 Dec 2011 09:53:38 +0200
> From: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
>
> When UDP RSS is enabled, we use same QPN for TCP and UDP ranges
> The bug is that the default_qpn was used base UDP qpn before it
> was set.
> Fixes bug introduced in commit: 1202d460b1df3a77fda66f4ba5f90ae3527dd42f
>
> Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
Applied.
^ permalink raw reply
* Re: macvtap rxhash patch
From: David Miller @ 2011-12-20 18:45 UTC (permalink / raw)
To: mst; +Cc: krkumar2, netdev
In-Reply-To: <20111220112326.GD3913@redhat.com>
From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Tue, 20 Dec 2011 13:23:26 +0200
> On Mon, Dec 19, 2011 at 04:37:32PM -0500, David Miller wrote:
>>
>> Reference:
>>
>> http://patchwork.ozlabs.org/patch/127456/
>>
>> This is just rotting for a long time, I want to just do something
>> with this patch, and I don't care if that's "apply it now" or
>> "defer indefinitely".
>>
>> Thanks.
>
> Ack, sorry about the delay.
No problem.
^ permalink raw reply
* Re: [PATCH] macvtap: Fix macvtap_get_queue to use rxhash first
From: David Miller @ 2011-12-20 18:46 UTC (permalink / raw)
To: mst; +Cc: krkumar2, arnd, netdev, virtualization, levinsasha928
In-Reply-To: <20111220111512.GA3913@redhat.com>
From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Tue, 20 Dec 2011 13:15:12 +0200
> On Wed, Dec 07, 2011 at 01:52:35PM -0500, David Miller wrote:
>> Once you sort this out, reply with an Acked-by: for me, thanks.
>
> Acked-by: Michael S. Tsirkin <mst@redhat.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next] net: unix -- Add missing module.h inclusion
From: David Miller @ 2011-12-20 18:47 UTC (permalink / raw)
To: gorcunov; +Cc: netdev, xemul
In-Reply-To: <20111220143303.GA12782@moon>
From: Cyrill Gorcunov <gorcunov@openvz.org>
Date: Tue, 20 Dec 2011 18:33:03 +0400
> Otherwise getting
>
> | net/unix/diag.c:312:16: error: expected declaration specifiers or ‘...’ before string constant
> | net/unix/diag.c:313:1: error: expected declaration specifiers or ‘...’ before string constant
>
> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Applied.
^ permalink raw reply
* Re: [PATCH v3] ARM: net: JIT compiler for packet filters
From: David Miller @ 2011-12-20 18:55 UTC (permalink / raw)
To: mgherzan; +Cc: linux-arm-kernel, netdev, linux
In-Reply-To: <1324404263-913-1-git-send-email-mgherzan@gmail.com>
From: Mircea Gherzan <mgherzan@gmail.com>
Date: Tue, 20 Dec 2011 19:04:23 +0100
> Based of Matt Evans's PPC64 implementation.
>
> The compiler generates ARM instructions but interworking is
> supported for Thumb2 kernels.
>
> Supports both little and big endian. Unaligned loads are emitted
> for ARMv6+. Not all the BPF opcodes that deal with ancillary data
> are supported. The scratch memory of the filter lives on the stack.
> Hardware integer division is used if it is available.
>
> Enabled in the same way as for x86-64 and PPC64:
>
> echo 1 > /proc/sys/net/core/bpf_jit_enable
>
> A value greater than 1 enables opcode output.
>
> Signed-off-by: Mircea Gherzan <mgherzan@gmail.com>
I'm happy with this going in via the ARM tree once all the details
are worked out:
Acked-by: David S. Miller <davem@davemloft.net>
^ permalink raw reply
* Re: [PATCH] batman-adv: checkpatch cleanup - remove lines longer than 80 chars
From: Marek Lindner @ 2011-12-20 18:59 UTC (permalink / raw)
To: David Miller
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r
In-Reply-To: <20111220.133230.713811345652751674.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
On Wednesday, December 21, 2011 02:32:30 David Miller wrote:
> From: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
> Date: Tue, 20 Dec 2011 18:38:24 +0800
>
> > The long line was introduced with b26e478f8f.
> >
> > Signed-off-by: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
>
> I'm not applying this.
>
> I tell people to make sure arguments line up correctly to the
> openning parenthesis on the previous line, and that is what is
> happening here.
I am not against lining up the arguments but what about checkpatch ? Are we
going to ignore the complaints or is this line limit about to be changed ?
Cheers,
Marek
^ permalink raw reply
* Re: [PATCH] sctp: Do not account for sizeof(struct sk_buff) in estimated rwnd
From: David Miller @ 2011-12-20 18:59 UTC (permalink / raw)
To: vladislav.yasevich; +Cc: weiyj.lk, linux-sctp, netdev
In-Reply-To: <4EF0CD69.9000602@hp.com>
From: Vlad Yasevich <vladislav.yasevich@hp.com>
Date: Tue, 20 Dec 2011 13:01:13 -0500
>
>
> On 12/20/2011 04:39 AM, Thomas Graf wrote:
>> On Tue, Dec 20, 2011 at 01:00:48PM +0800, Wei Yongjun wrote:
>>> I saw you discussed this with Vlad in old mail:
>>> http://www.spinics.net/lists/linux-sctp/msg01365.html
>>>
>>> You said you will update patch to include a per packet overhead,
>>> but it does not include in this patch, what's wrong with in?
>>
>> It's not possible because upon retransmission of a chunk we need
>> to readd the overhead to the rwnd. There is no longer a reference
>> to a packet so we can't know how much to add. This explanation is
>> also in the original mail thread.
>>
>
>
> Right. The original patches were done to work around the problem of
> leftover rwnd when socket buffer is exhausted and they didn't really
> address the problem sufficiently. It was still possible to reach that
> condition. Some subsequent patches added support to address this
> issue
> a different way. As a result, I think this revert is just fine.
>
> Acked-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Applied, thanks everyone.
^ permalink raw reply
* Re: [PATCH] batman-adv: checkpatch cleanup - remove lines longer than 80 chars
From: David Miller @ 2011-12-20 19:02 UTC (permalink / raw)
To: lindner_marek-LWAfsSFWpa4
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r
In-Reply-To: <201112210259.42387.lindner_marek-LWAfsSFWpa4@public.gmane.org>
From: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
Date: Wed, 21 Dec 2011 02:59:41 +0800
> On Wednesday, December 21, 2011 02:32:30 David Miller wrote:
>> From: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
>> Date: Tue, 20 Dec 2011 18:38:24 +0800
>>
>> > The long line was introduced with b26e478f8f.
>> >
>> > Signed-off-by: Marek Lindner <lindner_marek-LWAfsSFWpa4@public.gmane.org>
>>
>> I'm not applying this.
>>
>> I tell people to make sure arguments line up correctly to the
>> openning parenthesis on the previous line, and that is what is
>> happening here.
>
> I am not against lining up the arguments but what about checkpatch ? Are we
> going to ignore the complaints or is this line limit about to be changed ?
Refactor the code so that both constraints can be satisfied.
Is this so hard to understand?
^ permalink raw reply
* Re: [patch 00/10] s390: network driver features and fixes for net-next
From: David Miller @ 2011-12-20 19:05 UTC (permalink / raw)
To: frank.blaschka; +Cc: netdev, linux-s390
In-Reply-To: <20111220085626.924756639@de.ibm.com>
From: frank.blaschka@de.ibm.com
Date: Tue, 20 Dec 2011 09:56:26 +0100
> here are some s390 network driver features and fixes for net-next
Series applied, thanks.
^ permalink raw reply
* Re: [PATCH RFC] virtio_net: fix refill related races
From: Michael S. Tsirkin @ 2011-12-20 19:09 UTC (permalink / raw)
To: Rusty Russell; +Cc: Amit Shah, netdev, Tejun Heo, linux-kernel, virtualization
In-Reply-To: <87iplltd0g.fsf@rustcorp.com.au>
On Tue, Dec 13, 2011 at 01:05:11PM +1030, Rusty Russell wrote:
> On Mon, 12 Dec 2011 13:54:06 +0200, "Michael S. Tsirkin" <mst@redhat.com> wrote:
> > On Mon, Dec 12, 2011 at 09:25:07AM +1030, Rusty Russell wrote:
> > > Orthogonally, the refill-stop code is still buggy, as you noted.
> >
> > Sorry I don't understand how it's still buggy.
>
> Both places where we call:
>
> cancel_delayed_work_sync(&vi->refill);
>
> Do not actually guarantee that vi->refill isn't running, because it
> can requeue itself. A 'bool no_more_refill' field seems like the
> simplest fix for this, but I don't think it's sufficient.
>
> Tejun, is this correct? What's the correct way to synchronously stop a
> delayed_work which can "schedule_delayed_work(&vi->refill, HZ/2);" on
> itself?
>
> Thanks,
> Rusty.
Another question, wanted to make sure:
virtnet_poll does schedule_delayed_work(&vi->refill, 0);
separately refill work itself also does
schedule_delayed_work(&vi->refill, HZ/2);
If two such events happen twice, on different CPUs, we are still guaranteed
the work will only run once, right?
^ permalink raw reply
* Re: [PATCH] net: have ipconfig not wait if no dev is available
From: David Miller @ 2011-12-20 19:09 UTC (permalink / raw)
To: gerlando.falauto
Cc: micha, holger.brunck, kuznet, pekkas, jmorris, yoshfuji, kaber,
netdev, linux-kernel
In-Reply-To: <1324371484-24082-1-git-send-email-gerlando.falauto@keymile.com>
From: Gerlando Falauto <gerlando.falauto@keymile.com>
Date: Tue, 20 Dec 2011 09:58:04 +0100
> previous commit 3fb72f1e6e6165c5f495e8dc11c5bbd14c73385c
> makes IP-Config wait for carrier on at least one network device.
>
> Before waiting (predefined value 120s), check that at least one device
> was successfully brought up. Otherwise (e.g. buggy bootloader
> which does not set the MAC address) there is no point in waiting
> for carrier.
>
> Cc: Micha Nelissen <micha@neli.hopto.org>
> Cc: Holger Brunck <holger.brunck@keymile.com>
> Signed-off-by: Gerlando Falauto <gerlando.falauto@keymile.com>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH RFC] virtio_net: fix refill related races
From: Tejun Heo @ 2011-12-20 19:09 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: Amit Shah, netdev, linux-kernel, virtualization
In-Reply-To: <20111220190908.GC25689@redhat.com>
Hello, Michael.
On Tue, Dec 20, 2011 at 09:09:08PM +0200, Michael S. Tsirkin wrote:
> Another question, wanted to make sure:
> virtnet_poll does schedule_delayed_work(&vi->refill, 0);
> separately refill work itself also does
> schedule_delayed_work(&vi->refill, HZ/2);
> If two such events happen twice, on different CPUs, we are still guaranteed
> the work will only run once, right?
No, it's not. Normal workqueues only guarantee non-reentrance on
local CPU. If you want to guarantee that only one instance of a given
item is executing across all CPUs, you need to use the nrt workqueue.
Thanks.
--
tejun
^ permalink raw reply
* (unknown)
From: David Miller @ 2011-12-20 19:10 UTC (permalink / raw)
To: madalin.bucur; +Cc: steffen.klassert, eric.dumazet, timo.teras, netdev
In-Reply-To: <1324397163-302-1-git-send-email-madalin.bucur@freescale.com>
Please do not mangle, and in this case completely empty, the subject
line when replying to people.
It makes the thread impossible to follow, and people might miss your
posting entirely as I nearly did in this case.
^ permalink raw reply
* Re: [PATCH net-next ] net: doc: fix many typos in scaling.txt
From: David Miller @ 2011-12-20 19:12 UTC (permalink / raw)
To: shanwei88; +Cc: netdev
In-Reply-To: <4EEFF427.1090801@gmail.com>
From: Shan Wei <shanwei88@gmail.com>
Date: Tue, 20 Dec 2011 10:34:15 +0800
> Fix some trivial typos.
>
> Signed-off-by: Shan Wei <shanwei88@gmail.com>
Applied.
^ 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