* [PATCH v4 bpf-next 1/2] bpf: add cg_skb_is_valid_access for BPF_PROG_TYPE_CGROUP_SKB
From: Song Liu @ 2018-10-18 16:06 UTC (permalink / raw)
To: netdev; +Cc: ast, daniel, kernel-team, Song Liu
In-Reply-To: <20181018160649.1611530-1-songliubraving@fb.com>
BPF programs of BPF_PROG_TYPE_CGROUP_SKB need to access headers in the
skb. This patch enables direct access of skb for these programs.
Two helper functions bpf_compute_and_save_data_pointers() and
bpf_restore_data_pointers() are introduced. There are used in
__cgroup_bpf_run_filter_skb(), to compute proper data_end for the
BPF program, and restore original data afterwards.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
include/linux/filter.h | 24 ++++++++++++++++++++++++
kernel/bpf/cgroup.c | 6 ++++++
net/core/filter.c | 36 +++++++++++++++++++++++++++++++++++-
3 files changed, 65 insertions(+), 1 deletion(-)
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 5771874bc01e..96b3ee7f14c9 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -548,6 +548,30 @@ static inline void bpf_compute_data_pointers(struct sk_buff *skb)
cb->data_end = skb->data + skb_headlen(skb);
}
+/* Similar to bpf_compute_data_pointers(), except that save orginal
+ * data in cb->data and cb->meta_data for restore.
+ */
+static inline void bpf_compute_and_save_data_pointers(
+ struct sk_buff *skb, void *saved_pointers[2])
+{
+ struct bpf_skb_data_end *cb = (struct bpf_skb_data_end *)skb->cb;
+
+ saved_pointers[0] = cb->data_meta;
+ saved_pointers[1] = cb->data_end;
+ cb->data_meta = skb->data - skb_metadata_len(skb);
+ cb->data_end = skb->data + skb_headlen(skb);
+}
+
+/* Restore data saved by bpf_compute_data_pointers(). */
+static inline void bpf_restore_data_pointers(
+ struct sk_buff *skb, void *saved_pointers[2])
+{
+ struct bpf_skb_data_end *cb = (struct bpf_skb_data_end *)skb->cb;
+
+ cb->data_meta = saved_pointers[0];
+ cb->data_end = saved_pointers[1];;
+}
+
static inline u8 *bpf_skb_cb(struct sk_buff *skb)
{
/* eBPF programs may read/write skb->cb[] area to transfer meta
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 00f6ed2e4f9a..5f5180104ddc 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -554,6 +554,7 @@ int __cgroup_bpf_run_filter_skb(struct sock *sk,
unsigned int offset = skb->data - skb_network_header(skb);
struct sock *save_sk;
struct cgroup *cgrp;
+ void *saved_pointers[2];
int ret;
if (!sk || !sk_fullsock(sk))
@@ -566,8 +567,13 @@ int __cgroup_bpf_run_filter_skb(struct sock *sk,
save_sk = skb->sk;
skb->sk = sk;
__skb_push(skb, offset);
+
+ /* compute pointers for the bpf prog */
+ bpf_compute_and_save_data_pointers(skb, saved_pointers);
+
ret = BPF_PROG_RUN_ARRAY(cgrp->bpf.effective[type], skb,
bpf_prog_run_save_cb);
+ bpf_restore_data_pointers(skb, saved_pointers);
__skb_pull(skb, offset);
skb->sk = save_sk;
return ret == 1 ? 0 : -EPERM;
diff --git a/net/core/filter.c b/net/core/filter.c
index 1a3ac6c46873..e3ca30bd6840 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -5346,6 +5346,40 @@ static bool sk_filter_is_valid_access(int off, int size,
return bpf_skb_is_valid_access(off, size, type, prog, info);
}
+static bool cg_skb_is_valid_access(int off, int size,
+ enum bpf_access_type type,
+ const struct bpf_prog *prog,
+ struct bpf_insn_access_aux *info)
+{
+ switch (off) {
+ case bpf_ctx_range(struct __sk_buff, tc_classid):
+ case bpf_ctx_range(struct __sk_buff, data_meta):
+ case bpf_ctx_range(struct __sk_buff, flow_keys):
+ return false;
+ }
+ if (type == BPF_WRITE) {
+ switch (off) {
+ case bpf_ctx_range(struct __sk_buff, mark):
+ case bpf_ctx_range(struct __sk_buff, priority):
+ case bpf_ctx_range_till(struct __sk_buff, cb[0], cb[4]):
+ break;
+ default:
+ return false;
+ }
+ }
+
+ switch (off) {
+ case bpf_ctx_range(struct __sk_buff, data):
+ info->reg_type = PTR_TO_PACKET;
+ break;
+ case bpf_ctx_range(struct __sk_buff, data_end):
+ info->reg_type = PTR_TO_PACKET_END;
+ break;
+ }
+
+ return bpf_skb_is_valid_access(off, size, type, prog, info);
+}
+
static bool lwt_is_valid_access(int off, int size,
enum bpf_access_type type,
const struct bpf_prog *prog,
@@ -7038,7 +7072,7 @@ const struct bpf_prog_ops xdp_prog_ops = {
const struct bpf_verifier_ops cg_skb_verifier_ops = {
.get_func_proto = cg_skb_func_proto,
- .is_valid_access = sk_filter_is_valid_access,
+ .is_valid_access = cg_skb_is_valid_access,
.convert_ctx_access = bpf_convert_ctx_access,
};
--
2.17.1
^ permalink raw reply related
* [PATCH v4 bpf-next 2/2] bpf: add tests for direct packet access from CGROUP_SKB
From: Song Liu @ 2018-10-18 16:06 UTC (permalink / raw)
To: netdev; +Cc: ast, daniel, kernel-team, Song Liu
In-Reply-To: <20181018160649.1611530-1-songliubraving@fb.com>
Tests are added to make sure CGROUP_SKB cannot access:
tc_classid, data_meta, flow_keys
and can read and write:
mark, prority, and cb[0-4]
and can read other fields.
To make selftest with skb->sk work, a dummy sk is added in
bpf_prog_test_run_skb().
Signed-off-by: Song Liu <songliubraving@fb.com>
---
net/bpf/test_run.c | 7 +
tools/testing/selftests/bpf/test_verifier.c | 170 ++++++++++++++++++++
2 files changed, 177 insertions(+)
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
index 0c423b8cd75c..8dccac305268 100644
--- a/net/bpf/test_run.c
+++ b/net/bpf/test_run.c
@@ -10,6 +10,8 @@
#include <linux/etherdevice.h>
#include <linux/filter.h>
#include <linux/sched/signal.h>
+#include <net/sock.h>
+#include <net/tcp.h>
static __always_inline u32 bpf_test_run_one(struct bpf_prog *prog, void *ctx,
struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE])
@@ -115,6 +117,7 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
u32 retval, duration;
int hh_len = ETH_HLEN;
struct sk_buff *skb;
+ struct sock sk = {0};
void *data;
int ret;
@@ -137,11 +140,15 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
break;
}
+ sock_net_set(&sk, &init_net);
+ sock_init_data(NULL, &sk);
+
skb = build_skb(data, 0);
if (!skb) {
kfree(data);
return -ENOMEM;
}
+ skb->sk = &sk;
skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
__skb_put(skb, size);
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
index cf4cd32b6772..5bfba7e8afd7 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -4862,6 +4862,176 @@ static struct bpf_test tests[] = {
.result = REJECT,
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
},
+ {
+ "direct packet read test#1 for CGROUP_SKB",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+ offsetof(struct __sk_buff, data)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+ offsetof(struct __sk_buff, data_end)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1,
+ offsetof(struct __sk_buff, len)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1,
+ offsetof(struct __sk_buff, pkt_type)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
+ offsetof(struct __sk_buff, mark)),
+ BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_6,
+ offsetof(struct __sk_buff, mark)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1,
+ offsetof(struct __sk_buff, queue_mapping)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_8, BPF_REG_1,
+ offsetof(struct __sk_buff, protocol)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_1,
+ offsetof(struct __sk_buff, vlan_present)),
+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
+ BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1),
+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+ },
+ {
+ "direct packet read test#2 for CGROUP_SKB",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1,
+ offsetof(struct __sk_buff, vlan_tci)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1,
+ offsetof(struct __sk_buff, vlan_proto)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
+ offsetof(struct __sk_buff, priority)),
+ BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_6,
+ offsetof(struct __sk_buff, priority)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1,
+ offsetof(struct __sk_buff, ingress_ifindex)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_8, BPF_REG_1,
+ offsetof(struct __sk_buff, tc_index)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_1,
+ offsetof(struct __sk_buff, hash)),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+ },
+ {
+ "direct packet read test#3 for CGROUP_SKB",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1,
+ offsetof(struct __sk_buff, cb[0])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1,
+ offsetof(struct __sk_buff, cb[1])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
+ offsetof(struct __sk_buff, cb[2])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1,
+ offsetof(struct __sk_buff, cb[3])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_8, BPF_REG_1,
+ offsetof(struct __sk_buff, cb[4])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_1,
+ offsetof(struct __sk_buff, napi_id)),
+ BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_4,
+ offsetof(struct __sk_buff, cb[0])),
+ BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_5,
+ offsetof(struct __sk_buff, cb[1])),
+ BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_6,
+ offsetof(struct __sk_buff, cb[2])),
+ BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_7,
+ offsetof(struct __sk_buff, cb[3])),
+ BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_8,
+ offsetof(struct __sk_buff, cb[4])),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+ },
+ {
+ "direct packet read test#4 for CGROUP_SKB",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+ offsetof(struct __sk_buff, family)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+ offsetof(struct __sk_buff, remote_ip4)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1,
+ offsetof(struct __sk_buff, local_ip4)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1,
+ offsetof(struct __sk_buff, remote_ip6[0])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1,
+ offsetof(struct __sk_buff, remote_ip6[1])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1,
+ offsetof(struct __sk_buff, remote_ip6[2])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1,
+ offsetof(struct __sk_buff, remote_ip6[3])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
+ offsetof(struct __sk_buff, local_ip6[0])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
+ offsetof(struct __sk_buff, local_ip6[1])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
+ offsetof(struct __sk_buff, local_ip6[2])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
+ offsetof(struct __sk_buff, local_ip6[3])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1,
+ offsetof(struct __sk_buff, remote_port)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_8, BPF_REG_1,
+ offsetof(struct __sk_buff, local_port)),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+ },
+ {
+ "invalid access of tc_classid for CGROUP_SKB",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, tc_classid)),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .result = REJECT,
+ .errstr = "invalid bpf_context access",
+ .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+ },
+ {
+ "invalid access of data_meta for CGROUP_SKB",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, data_meta)),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .result = REJECT,
+ .errstr = "invalid bpf_context access",
+ .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+ },
+ {
+ "invalid access of flow_keys for CGROUP_SKB",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, flow_keys)),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .result = REJECT,
+ .errstr = "invalid bpf_context access",
+ .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+ },
+ {
+ "invalid write access to napi_id for CGROUP_SKB",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_1,
+ offsetof(struct __sk_buff, napi_id)),
+ BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_9,
+ offsetof(struct __sk_buff, napi_id)),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .result = REJECT,
+ .errstr = "invalid bpf_context access",
+ .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+ },
{
"valid cgroup storage access",
.insns = {
--
2.17.1
^ permalink raw reply related
* [PATCH v4 bpf-next 0/2] bpf: add cg_skb_is_valid_access
From: Song Liu @ 2018-10-18 16:06 UTC (permalink / raw)
To: netdev; +Cc: ast, daniel, kernel-team, Song Liu
Changes v3 -> v4:
1. Fixed crash issue reported by Alexei.
Changes v2 -> v3:
1. Added helper function bpf_compute_and_save_data_pointers() and
bpf_restore_data_pointers().
Changes v1 -> v2:
1. Updated the list of read-only fields, and read-write fields.
2. Added dummy sk to bpf_prog_test_run_skb().
This set enables BPF program of type BPF_PROG_TYPE_CGROUP_SKB to access
some __skb_buff data directly.
Song Liu (2):
bpf: add cg_skb_is_valid_access for BPF_PROG_TYPE_CGROUP_SKB
bpf: add tests for direct packet access from CGROUP_SKB
include/linux/filter.h | 24 +++
kernel/bpf/cgroup.c | 6 +
net/bpf/test_run.c | 7 +
net/core/filter.c | 36 ++++-
tools/testing/selftests/bpf/test_verifier.c | 170 ++++++++++++++++++++
5 files changed, 242 insertions(+), 1 deletion(-)
^ permalink raw reply
* Photos 39
From: Nancy @ 2018-10-18 11:24 UTC (permalink / raw)
To: netdev
We are an image team who can process 400+ images each day.
If you need any image editing service, please let us know.
Image cut out and clipping path, masking.
Such as for ecommerce photos, jewelry photos retouching, beauty and skin
images
and wedding photos.
We give test editing for your photos if you send us some.
Thanks,
Nancy
^ permalink raw reply
* Photos 39
From: Nancy @ 2018-10-18 10:01 UTC (permalink / raw)
To: netdev
We are an image team who can process 400+ images each day.
If you need any image editing service, please let us know.
Image cut out and clipping path, masking.
Such as for ecommerce photos, jewelry photos retouching, beauty and skin
images
and wedding photos.
We give test editing for your photos if you send us some.
Thanks,
Nancy
^ permalink raw reply
* [PATCH net-next] tcp: fix TCP_REPAIR xmit queue setup
From: Eric Dumazet @ 2018-10-18 16:12 UTC (permalink / raw)
To: David S . Miller, Neal Cardwell, Soheil Hassas Yeganeh,
Andrey Vagin
Cc: netdev, Eric Dumazet, Eric Dumazet
Andrey reported the following warning triggered while running CRIU tests:
tcp_clean_rtx_queue()
...
last_ackt = tcp_skb_timestamp_us(skb);
WARN_ON_ONCE(last_ackt == 0);
This is caused by 5f6188a8003d ("tcp: do not change tcp_wstamp_ns
in tcp_mstamp_refresh"), as we end up having skbs in retransmit queue
with a zero skb->skb_mstamp_ns field.
We could fix this bug in different ways, like making sure
tp->tcp_wstamp_ns is not zero at socket creation, but as Neal pointed
out, we also do not want that pacing status of a repaired socket
could push tp->tcp_wstamp_ns far ahead in the future.
So we prefer changing tcp_write_xmit() to not call tcp_update_skb_after_send()
and instead do what is requested by TCP_REPAIR logic.
Fixes: 5f6188a8003d ("tcp: do not change tcp_wstamp_ns in tcp_mstamp_refresh")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Andrey Vagin <avagin@openvz.org>
Acked-by: Soheil Hassas Yeganeh <soheil@google.com>
Acked-by: Neal Cardwell <ncardwell@google.com>
---
net/ipv4/tcp_output.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index d212e4cbc68902e873afb4a12b43b467ccd6069b..c07990a35ff3bd9438d32c82863ef207c93bdb9e 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2321,18 +2321,19 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
while ((skb = tcp_send_head(sk))) {
unsigned int limit;
- if (tcp_pacing_check(sk))
- break;
-
- tso_segs = tcp_init_tso_segs(skb, mss_now);
- BUG_ON(!tso_segs);
-
if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) {
- /* "skb_mstamp" is used as a start point for the retransmit timer */
- tcp_update_skb_after_send(sk, skb, tp->tcp_wstamp_ns);
+ /* "skb_mstamp_ns" is used as a start point for the retransmit timer */
+ skb->skb_mstamp_ns = tp->tcp_wstamp_ns = tp->tcp_clock_cache;
+ list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue);
goto repair; /* Skip network transmission */
}
+ if (tcp_pacing_check(sk))
+ break;
+
+ tso_segs = tcp_init_tso_segs(skb, mss_now);
+ BUG_ON(!tso_segs);
+
cwnd_quota = tcp_cwnd_test(tp, skb);
if (!cwnd_quota) {
if (push_one == 2)
--
2.19.1.331.ge82ca0e54c-goog
^ permalink raw reply related
* linux-next: build failure after merge of the net-next tree
From: Stephen Rothwell @ 2018-10-19 0:18 UTC (permalink / raw)
To: David Miller, Networking, Doug Ledford, Jason Gunthorpe
Cc: Linux-Next Mailing List, Linux Kernel Mailing List, Mark Bloch,
Leon Romanovsky, Paul Blakey, Saeed Mahameed
[-- Attachment #1: Type: text/plain, Size: 1539 bytes --]
Hi all,
After merging the net-next tree, today's linux-next build (x86_64
allmodconfig) failed like this:
drivers/infiniband/hw/mlx5/flow.c: In function 'mlx5_ib_handler_MLX5_IB_METHOD_CREATE_FLOW':
drivers/infiniband/hw/mlx5/flow.c:163:12: error: 'struct mlx5_flow_act' has no member named 'has_flow_tag'; did you mean 'flow_tag'?
flow_act.has_flow_tag = true;
^~~~~~~~~~~~
flow_tag
Caused by commit
d5634fee245f ("net/mlx5: Add a no-append flow insertion mode")
interacting with commit
ba4a41198324 ("RDMA/mlx5: Add support for flow tag to raw create flow")
from the rdma tree.
I have applied the following merge fix patch for today:
From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Fri, 19 Oct 2018 11:10:39 +1100
Subject: [PATCH] net/mlx5: fix up for has_flow_tag changing to a flag
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
drivers/infiniband/hw/mlx5/flow.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/infiniband/hw/mlx5/flow.c b/drivers/infiniband/hw/mlx5/flow.c
index e57435cb6d96..f86cdcafdafc 100644
--- a/drivers/infiniband/hw/mlx5/flow.c
+++ b/drivers/infiniband/hw/mlx5/flow.c
@@ -160,7 +160,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)(
ret = -EINVAL;
goto err_out;
}
- flow_act.has_flow_tag = true;
+ flow_act.flags |= FLOW_ACT_HAS_TAG;
}
flow_handler = mlx5_ib_raw_fs_rule_add(dev, fs_matcher, &flow_act,
--
2.18.0
--
Cheers,
Stephen Rothwell
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply related
* Re: [iproute PATCH] rdma: Fix for ineffective check in add_filter()
From: Phil Sutter @ 2018-10-18 16:17 UTC (permalink / raw)
To: David Ahern
Cc: Stephen Hemminger, netdev, Arkadi Sharshevsky, Leon Romanovsky
In-Reply-To: <6b365665-100c-d6e2-56bd-dfac39b55806@gmail.com>
Hi,
On Thu, Oct 18, 2018 at 09:27:47AM -0600, David Ahern wrote:
> On 10/18/18 5:41 AM, Phil Sutter wrote:
> > With 'name' field defined as array in struct filters, it will always
> > contain a value irrespective of whether a name was assigned or not.
> >
> > Fix this by turning the field into a const char pointer.
> >
> > Fixes: 8cd644095842a ("devlink: Add support for devlink resource abstraction")
>
> Stale paste buffer? Seems like the correct tag is
> Fixes: 1174be72d1b4c ("rdma: Add filtering infrastructure")
Oh, indeed. Also the wrong person in Cc: Arkadi is innocent, culprit
patch came from Leon.
Stephen, should I respin or will you correct the Fixes tag?
Thanks, Phil
^ permalink raw reply
* [GIT] Networking
From: David Miller @ 2018-10-19 0:19 UTC (permalink / raw)
To: gregkh; +Cc: akpm, netdev, linux-kernel
1) Fix gro_cells leak in xfrm layer, from Li RongQing.
2) BPF selftests change RLIMIT_MEMLOCK blindly, don't do that.
From Eric Dumazet.
3) AF_XDP calls synchronize_net() under RCU lock, fix from Björn
Töpel.
4) Out of bounds packet access in _decode_session6(), from Alexei
Starovoitov.
5) Several ethtool bugs, where we copy a struct into the kernel
twice and our validations of the values in the first copy can
be invalidated by the second copy due to asynchronous updates
to the memory by the user. From Wenwen Wang.
6) Missing netlink attribute validation in cls_api, from Davide
Caratti.
7) LLC SAP sockets neet to be SOCK_RCU FREE, from Cong Wang.
8) rxrpc operates on wrong kvec, from Yue Haibing.
9) A regression was introduced by the disassosciation of route
neighbour references in rt6_probe(), causing probe for
neighbourless routes to not be properly rate limited. Fix
from Sabrina Dubroca.
10) Unsafe RCU locking in tipc, from Tung Nguyen.
11) Use after free in inet6_mc_check(), from Eric Dumazet.
12) PMTU from icmp packets should update the SCTP transport
pathmtu, from Xin Long.
13) Missing peer put on error in rxrpc, from David Howells.
14) Fix pedit in nfp driver, from Pieter Jansen van Vuuren.
15) Fix overflowing shift statement in qla3xxx driver, from Nathan
Chancellor.
16) Fix Spectre v1 in ptp code, from Gustavo A. R. Silva.
17) udp6_unicast_rcv_skb() interprets udpv6_queue_rcv_skb() return
value in an inverted manner, fix from Paolo Abeni.
18) Fix missed unresolved entries in ipmr dumps, from Nikolay
Aleksandrov.
19) Fix NAPI handling under high load, we can completely miss events
when NAPI has to loop more than one time in a cycle. From Heiner
Kallweit.
Please pull, thanks a lot!
The following changes since commit bab5c80b211035739997ebd361a679fa85b39465:
Merge tag 'armsoc-fixes-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc (2018-10-12 17:41:27 +0200)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
for you to fetch changes up to d4d576f5ab7edcb757bb33e6a5600666a0b1232d:
ip6_tunnel: Fix encapsulation layout (2018-10-18 16:54:40 -0700)
----------------------------------------------------------------
Ake Koomsin (1):
virtio_net: avoid using netif_tx_disable() for serializing tx routine
Alexei Starovoitov (1):
net/xfrm: fix out-of-bounds packet access
Björn Töpel (1):
xsk: do not call synchronize_net() under RCU read lock
Colin Ian King (1):
qed: fix spelling mistake "Ireelevant" -> "Irrelevant"
Cong Wang (1):
llc: set SOCK_RCU_FREE in llc_sap_add_socket()
David Howells (3):
rxrpc: Fix an uninitialised variable
rxrpc: Fix incorrect conditional on IPV6
rxrpc: Fix a missing rxrpc_put_peer() in the error_report handler
David S. Miller (5):
Merge git://git.kernel.org/.../bpf/bpf
Merge tag 'mlx5-fixes-2018-10-10' of git://git.kernel.org/.../saeed/linux
Merge branch 'nfp-fix-pedit-set-action-offloads'
Merge branch 'geneve-vxlan-mtu'
Merge branch 'master' of git://git.kernel.org/.../klassert/ipsec
Davide Caratti (1):
net/sched: cls_api: add missing validation of netlink attributes
Eric Dumazet (2):
bpf: do not blindly change rlimit in reuseport net selftest
ipv6: mcast: fix a use-after-free in inet6_mc_check
Florian Fainelli (1):
net: bcmgenet: Poll internal PHY for GENETv5
Florian Westphal (1):
xfrm: policy: use hlist rcu variants on insert
Fugang Duan (1):
net: fec: don't dump RX FIFO register when not available
Gregory CLEMENT (1):
net: mscc: ocelot: Fix comment in ocelot_vlant_wait_for_completion()
Gustavo A. R. Silva (1):
ptp: fix Spectre v1 vulnerability
Heiner Kallweit (2):
r8169: re-enable MSI-X on RTL8168g
r8169: fix NAPI handling under high load
Huy Nguyen (1):
net/mlx5: Take only bit 24-26 of wqe.pftype_wq for page fault type
Ido Schimmel (1):
mlxsw: core: Fix use-after-free when flashing firmware during init
Jian-Hong Pan (1):
r8169: Enable MSI-X on RTL8106e
Jon Maloy (2):
tipc: initialize broadcast link stale counter correctly
tipc: fix info leak from kernel tipc_event
Li RongQing (1):
xfrm: fix gro_cells leak when remove virtual xfrm interfaces
Marcelo Ricardo Leitner (1):
sctp: fix race on sctp_id2asoc
Nathan Chancellor (1):
net: qla3xxx: Remove overflowing shift statement
Nikolay Aleksandrov (1):
net: ipmr: fix unresolved entry dumps
Paolo Abeni (1):
udp6: fix encap return code for resubmitting
Phil Sutter (1):
net: sched: Fix for duplicate class dump
Pieter Jansen van Vuuren (3):
nfp: flower: fix pedit set actions for multiple partial masks
nfp: flower: fix multiple keys per pedit action
nfp: flower: use offsets provided by pedit instead of index for ipv6
Sabrina Dubroca (1):
ipv6: rate-limit probes for neighbourless routes
Stefano Brivio (3):
geneve, vxlan: Don't check skb_dst() twice
geneve, vxlan: Don't set exceptions if skb->len < mtu
ip6_tunnel: Fix encapsulation layout
Steffen Klassert (1):
MAINTAINERS: Remove net/core/flow.c
Taehee Yoo (1):
net: bpfilter: use get_pid_task instead of pid_task
Talat Batheesh (1):
net/mlx5: Fix memory leak when setting fpga ipsec caps
Tariq Toukan (1):
net/mlx5: WQ, fixes for fragmented WQ buffers API
Tung Nguyen (1):
tipc: fix unsafe rcu locking when accessing publication list
Wenwen Wang (3):
ethtool: fix a missing-check bug
ethtool: fix a privilege escalation bug
net: socket: fix a missing-check bug
Xin Long (4):
sctp: use the pmtu from the icmp packet to update transport pathmtu
sctp: get pr_assoc and pr_stream all status with SCTP_PR_SCTP_ALL instead
sctp: not free the new asoc when sctp_wait_for_connect returns err
sctp: fix the data size calculation in sctp_data_size
YueHaibing (1):
rxrpc: use correct kvec num when sending BUSY response packet
MAINTAINERS | 1 -
drivers/net/ethernet/broadcom/genet/bcmmii.c | 7 +++++--
drivers/net/ethernet/freescale/fec.h | 4 ++++
drivers/net/ethernet/freescale/fec_main.c | 16 ++++++++++++----
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 12 +++++-------
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 22 +++++++++++-----------
drivers/net/ethernet/mellanox/mlx5/core/eq.c | 2 +-
drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c | 9 ++++-----
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h | 5 ++---
drivers/net/ethernet/mellanox/mlx5/core/wq.c | 5 -----
drivers/net/ethernet/mellanox/mlx5/core/wq.h | 11 +++++------
drivers/net/ethernet/mellanox/mlxsw/core.c | 2 ++
drivers/net/ethernet/mellanox/mlxsw/core.h | 4 ++++
drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 17 +++++++++++------
drivers/net/ethernet/mscc/ocelot.c | 6 +++---
drivers/net/ethernet/netronome/nfp/flower/action.c | 51 +++++++++++++++++++++++++++++++++------------------
drivers/net/ethernet/qlogic/qed/qed_int.c | 2 +-
drivers/net/ethernet/qlogic/qla3xxx.c | 2 --
drivers/net/ethernet/realtek/r8169.c | 20 +++++---------------
drivers/net/geneve.c | 14 +++-----------
drivers/net/virtio_net.c | 5 ++++-
drivers/net/vxlan.c | 12 ++----------
drivers/ptp/ptp_chardev.c | 4 ++++
include/linux/mlx5/driver.h | 8 ++++++++
include/net/dst.h | 10 ++++++++++
include/net/ip6_fib.h | 4 ++++
include/net/sctp/sm.h | 2 +-
include/net/sctp/structs.h | 2 ++
include/uapi/linux/sctp.h | 1 +
kernel/bpf/xskmap.c | 10 ++--------
net/bpfilter/bpfilter_kern.c | 6 ++++--
net/core/ethtool.c | 11 +++++++++--
net/ipv4/ipmr_base.c | 2 --
net/ipv6/ip6_tunnel.c | 10 +++++-----
net/ipv6/mcast.c | 16 ++++++++--------
net/ipv6/route.c | 12 ++++++------
net/ipv6/udp.c | 6 ++----
net/ipv6/xfrm6_policy.c | 4 ++--
net/llc/llc_conn.c | 1 +
net/rxrpc/call_accept.c | 2 +-
net/rxrpc/local_object.c | 2 +-
net/rxrpc/output.c | 3 ++-
net/rxrpc/peer_event.c | 1 +
net/sched/cls_api.c | 13 ++++++++-----
net/sched/sch_api.c | 11 ++++++-----
net/sctp/associola.c | 3 ++-
net/sctp/input.c | 1 +
net/sctp/output.c | 6 ++++++
net/sctp/socket.c | 17 +++++++++--------
net/socket.c | 11 ++++++++---
net/tipc/group.c | 1 +
net/tipc/link.c | 1 +
net/tipc/name_distr.c | 4 ++--
net/xdp/xsk.c | 2 ++
net/xfrm/xfrm_interface.c | 3 +++
net/xfrm/xfrm_policy.c | 8 ++++----
tools/testing/selftests/net/reuseport_bpf.c | 13 +++++++++----
57 files changed, 253 insertions(+), 187 deletions(-)
^ permalink raw reply
* Re: [PATCH v2] isdn: hfc_{pci,sx}: Avoid empty body if statements
From: Nathan Chancellor @ 2018-10-19 0:21 UTC (permalink / raw)
To: David Miller; +Cc: isdn, netdev, linux-kernel, yamada.masahiro
In-Reply-To: <20181018.154219.1246620018001438422.davem@davemloft.net>
On Thu, Oct 18, 2018 at 03:42:19PM -0700, David Miller wrote:
> From: Nathan Chancellor <natechancellor@gmail.com>
> Date: Wed, 17 Oct 2018 20:49:36 -0700
>
> > @@ -228,8 +228,8 @@ typedef union {
> > } fifo_area;
> >
> >
> > -#define Write_hfc(a, b, c) (*(((u_char *)a->hw.hfcpci.pci_io) + b) = c)
> > -#define Read_hfc(a, b) (*(((u_char *)a->hw.hfcpci.pci_io) + b))
> > +#define Write_hfc(a, b, c) (writeb(c, (a->hw.hfcpci.pci_io) + b))
> > +#define Read_hfc(a, b) (readb((a->hw.hfcpci.pci_io) + b))
>
> This will add new kinds of warnings.
>
> The problem is that readb/writeb/etc. take an __iomem pointer, but pci_io
> is declared as plain "unsigned char *". It should be something like
> "void * __iomem" of similar.
Thanks for the review, I went ahead and compiled with the following diff
on top of v2 and got no warnings from Clang, GCC, or sparse, does this
seem satisfactory for v3?
Nathan
========================================================================
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 7bcd104e9dfe..3dbaee8c604f 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -86,7 +86,7 @@ release_io_hfcpci(struct IsdnCardState *cs)
pci_free_consistent(cs->hw.hfcpci.dev, 0x8000,
cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma);
cs->hw.hfcpci.fifos = NULL;
- iounmap((void *)cs->hw.hfcpci.pci_io);
+ iounmap(cs->hw.hfcpci.pci_io);
}
/********************************************************************************/
@@ -1692,7 +1692,7 @@ setup_hfcpci(struct IsdnCard *card)
printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
return (0);
}
- cs->hw.hfcpci.pci_io = (char *)(unsigned long)dev_hfcpci->resource[1].start;
+ cs->hw.hfcpci.pci_io = (void __iomem *)(unsigned long)dev_hfcpci->resource[1].start;
printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
if (!cs->hw.hfcpci.pci_io) {
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 338d0408b377..40080e06421c 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -703,7 +703,7 @@ struct hfcPCI_hw {
unsigned char nt_mode;
int nt_timer;
struct pci_dev *dev;
- unsigned char *pci_io; /* start of PCI IO memory */
+ void __iomem *pci_io; /* start of PCI IO memory */
dma_addr_t dma; /* dma handle for Fifos */
void *fifos; /* FIFO memory */
int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */
^ permalink raw reply related
* Re: [PATCH v2] isdn: hfc_{pci,sx}: Avoid empty body if statements
From: David Miller @ 2018-10-19 0:23 UTC (permalink / raw)
To: natechancellor; +Cc: isdn, netdev, linux-kernel, yamada.masahiro
In-Reply-To: <20181019002117.GA10161@flashbox>
From: Nathan Chancellor <natechancellor@gmail.com>
Date: Thu, 18 Oct 2018 17:21:17 -0700
> Thanks for the review, I went ahead and compiled with the following diff
> on top of v2 and got no warnings from Clang, GCC, or sparse, does this
> seem satisfactory for v3?
Well, one thing I notice.
> @@ -86,7 +86,7 @@ release_io_hfcpci(struct IsdnCardState *cs)
> pci_free_consistent(cs->hw.hfcpci.dev, 0x8000,
> cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma);
> cs->hw.hfcpci.fifos = NULL;
> - iounmap((void *)cs->hw.hfcpci.pci_io);
> + iounmap(cs->hw.hfcpci.pci_io);
> }
Driver uses iounmap().
> @@ -1692,7 +1692,7 @@ setup_hfcpci(struct IsdnCard *card)
> printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
> return (0);
> }
> - cs->hw.hfcpci.pci_io = (char *)(unsigned long)dev_hfcpci->resource[1].start;
> + cs->hw.hfcpci.pci_io = (void __iomem *)(unsigned long)dev_hfcpci->resource[1].start;
> printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
But does not use iomap(). You won't need any cast here if it did use
iomap() properly.
Thanks.
^ permalink raw reply
* Re: [PATCH bpf-next v3 5/7] bpf: add MAP_LOOKUP_AND_DELETE_ELEM syscall
From: Song Liu @ 2018-10-18 16:26 UTC (permalink / raw)
To: mauricio.vasquez; +Cc: Alexei Starovoitov, Daniel Borkmann, Networking
In-Reply-To: <153986859079.9127.4059154863687596764.stgit@kernel>
On Thu, Oct 18, 2018 at 6:16 AM Mauricio Vasquez B
<mauricio.vasquez@polito.it> wrote:
>
> The previous patch implemented a bpf queue/stack maps that
> provided the peek/pop/push functions. There is not a direct
> relationship between those functions and the current maps
> syscalls, hence a new MAP_LOOKUP_AND_DELETE_ELEM syscall is added,
> this is mapped to the pop operation in the queue/stack maps
> and it is still to implement in other kind of maps.
>
> Signed-off-by: Mauricio Vasquez B <mauricio.vasquez@polito.it>
Acked-by: Song Liu <songliubraving@fb.com>
> ---
> include/uapi/linux/bpf.h | 1 +
> kernel/bpf/syscall.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 67 insertions(+)
>
> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index b8fc161c5b78..c8824d5364ff 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
> @@ -103,6 +103,7 @@ enum bpf_cmd {
> BPF_BTF_LOAD,
> BPF_BTF_GET_FD_BY_ID,
> BPF_TASK_FD_QUERY,
> + BPF_MAP_LOOKUP_AND_DELETE_ELEM,
> };
>
> enum bpf_map_type {
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index 1617407f9ee5..49ae64a26562 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -999,6 +999,69 @@ static int map_get_next_key(union bpf_attr *attr)
> return err;
> }
>
> +#define BPF_MAP_LOOKUP_AND_DELETE_ELEM_LAST_FIELD value
> +
> +static int map_lookup_and_delete_elem(union bpf_attr *attr)
> +{
> + void __user *ukey = u64_to_user_ptr(attr->key);
> + void __user *uvalue = u64_to_user_ptr(attr->value);
> + int ufd = attr->map_fd;
> + struct bpf_map *map;
> + void *key, *value, *ptr;
> + u32 value_size;
> + struct fd f;
> + int err;
> +
> + if (CHECK_ATTR(BPF_MAP_LOOKUP_AND_DELETE_ELEM))
> + return -EINVAL;
> +
> + f = fdget(ufd);
> + map = __bpf_map_get(f);
> + if (IS_ERR(map))
> + return PTR_ERR(map);
> +
> + if (!(f.file->f_mode & FMODE_CAN_WRITE)) {
> + err = -EPERM;
> + goto err_put;
> + }
> +
> + key = __bpf_copy_key(ukey, map->key_size);
> + if (IS_ERR(key)) {
> + err = PTR_ERR(key);
> + goto err_put;
> + }
> +
> + value_size = map->value_size;
> +
> + err = -ENOMEM;
> + value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
> + if (!value)
> + goto free_key;
> +
> + if (map->map_type == BPF_MAP_TYPE_QUEUE ||
> + map->map_type == BPF_MAP_TYPE_STACK) {
> + err = map->ops->map_pop_elem(map, value);
> + } else {
> + err = -ENOTSUPP;
> + }
> +
> + if (err)
> + goto free_value;
> +
> + if (copy_to_user(uvalue, value, value_size) != 0)
> + goto free_value;
> +
> + err = 0;
> +
> +free_value:
> + kfree(value);
> +free_key:
> + kfree(key);
> +err_put:
> + fdput(f);
> + return err;
> +}
> +
> static const struct bpf_prog_ops * const bpf_prog_types[] = {
> #define BPF_PROG_TYPE(_id, _name) \
> [_id] = & _name ## _prog_ops,
> @@ -2472,6 +2535,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
> case BPF_TASK_FD_QUERY:
> err = bpf_task_fd_query(&attr, uattr);
> break;
> + case BPF_MAP_LOOKUP_AND_DELETE_ELEM:
> + err = map_lookup_and_delete_elem(&attr);
> + break;
> default:
> err = -EINVAL;
> break;
>
^ permalink raw reply
* Re: [PATCH bpf-next v3 4/7] bpf: add queue and stack maps
From: Song Liu @ 2018-10-18 16:27 UTC (permalink / raw)
To: mauricio.vasquez; +Cc: Alexei Starovoitov, Daniel Borkmann, Networking
In-Reply-To: <153986858555.9127.14517764371945179514.stgit@kernel>
On Thu, Oct 18, 2018 at 6:16 AM Mauricio Vasquez B
<mauricio.vasquez@polito.it> wrote:
>
> Queue/stack maps implement a FIFO/LIFO data storage for ebpf programs.
> These maps support peek, pop and push operations that are exposed to eBPF
> programs through the new bpf_map[peek/pop/push] helpers. Those operations
> are exposed to userspace applications through the already existing
> syscalls in the following way:
>
> BPF_MAP_LOOKUP_ELEM -> peek
> BPF_MAP_LOOKUP_AND_DELETE_ELEM -> pop
> BPF_MAP_UPDATE_ELEM -> push
>
> Queue/stack maps are implemented using a buffer, tail and head indexes,
> hence BPF_F_NO_PREALLOC is not supported.
>
> As opposite to other maps, queue and stack do not use RCU for protecting
> maps values, the bpf_map[peek/pop] have a ARG_PTR_TO_UNINIT_MAP_VALUE
> argument that is a pointer to a memory zone where to save the value of a
> map. Basically the same as ARG_PTR_TO_UNINIT_MEM, but the size has not
> be passed as an extra argument.
>
> Our main motivation for implementing queue/stack maps was to keep track
> of a pool of elements, like network ports in a SNAT, however we forsee
> other use cases, like for exampling saving last N kernel events in a map
> and then analysing from userspace.
>
> Signed-off-by: Mauricio Vasquez B <mauricio.vasquez@polito.it>
Acked-by: Song Liu <songliubraving@fb.com>
> ---
> include/linux/bpf.h | 6 +
> include/linux/bpf_types.h | 2
> include/uapi/linux/bpf.h | 29 ++++
> kernel/bpf/Makefile | 2
> kernel/bpf/core.c | 3
> kernel/bpf/helpers.c | 43 ++++++
> kernel/bpf/queue_stack_maps.c | 288 +++++++++++++++++++++++++++++++++++++++++
> kernel/bpf/syscall.c | 6 +
> kernel/bpf/verifier.c | 19 +++
> net/core/filter.c | 6 +
> 10 files changed, 401 insertions(+), 3 deletions(-)
> create mode 100644 kernel/bpf/queue_stack_maps.c
>
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 0f8b863e0229..33014ae73103 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -39,6 +39,9 @@ struct bpf_map_ops {
> void *(*map_lookup_elem)(struct bpf_map *map, void *key);
> int (*map_update_elem)(struct bpf_map *map, void *key, void *value, u64 flags);
> int (*map_delete_elem)(struct bpf_map *map, void *key);
> + int (*map_push_elem)(struct bpf_map *map, void *value, u64 flags);
> + int (*map_pop_elem)(struct bpf_map *map, void *value);
> + int (*map_peek_elem)(struct bpf_map *map, void *value);
>
> /* funcs called by prog_array and perf_event_array map */
> void *(*map_fd_get_ptr)(struct bpf_map *map, struct file *map_file,
> @@ -811,6 +814,9 @@ static inline int bpf_fd_reuseport_array_update_elem(struct bpf_map *map,
> extern const struct bpf_func_proto bpf_map_lookup_elem_proto;
> extern const struct bpf_func_proto bpf_map_update_elem_proto;
> extern const struct bpf_func_proto bpf_map_delete_elem_proto;
> +extern const struct bpf_func_proto bpf_map_push_elem_proto;
> +extern const struct bpf_func_proto bpf_map_pop_elem_proto;
> +extern const struct bpf_func_proto bpf_map_peek_elem_proto;
>
> extern const struct bpf_func_proto bpf_get_prandom_u32_proto;
> extern const struct bpf_func_proto bpf_get_smp_processor_id_proto;
> diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h
> index 7bad4e1947ed..44d9ab4809bd 100644
> --- a/include/linux/bpf_types.h
> +++ b/include/linux/bpf_types.h
> @@ -69,3 +69,5 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_XSKMAP, xsk_map_ops)
> BPF_MAP_TYPE(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, reuseport_array_ops)
> #endif
> #endif
> +BPF_MAP_TYPE(BPF_MAP_TYPE_QUEUE, queue_map_ops)
> +BPF_MAP_TYPE(BPF_MAP_TYPE_STACK, stack_map_ops)
> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index f9187b41dff6..b8fc161c5b78 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
> @@ -128,6 +128,8 @@ enum bpf_map_type {
> BPF_MAP_TYPE_CGROUP_STORAGE,
> BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
> BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
> + BPF_MAP_TYPE_QUEUE,
> + BPF_MAP_TYPE_STACK,
> };
>
> enum bpf_prog_type {
> @@ -462,6 +464,28 @@ union bpf_attr {
> * Return
> * 0 on success, or a negative error in case of failure.
> *
> + * int bpf_map_push_elem(struct bpf_map *map, const void *value, u64 flags)
> + * Description
> + * Push an element *value* in *map*. *flags* is one of:
> + *
> + * **BPF_EXIST**
> + * If the queue/stack is full, the oldest element is removed to
> + * make room for this.
> + * Return
> + * 0 on success, or a negative error in case of failure.
> + *
> + * int bpf_map_pop_elem(struct bpf_map *map, void *value)
> + * Description
> + * Pop an element from *map*.
> + * Return
> + * 0 on success, or a negative error in case of failure.
> + *
> + * int bpf_map_peek_elem(struct bpf_map *map, void *value)
> + * Description
> + * Get an element from *map* without removing it.
> + * Return
> + * 0 on success, or a negative error in case of failure.
> + *
> * int bpf_probe_read(void *dst, u32 size, const void *src)
> * Description
> * For tracing programs, safely attempt to read *size* bytes from
> @@ -2303,7 +2327,10 @@ union bpf_attr {
> FN(skb_ancestor_cgroup_id), \
> FN(sk_lookup_tcp), \
> FN(sk_lookup_udp), \
> - FN(sk_release),
> + FN(sk_release), \
> + FN(map_push_elem), \
> + FN(map_pop_elem), \
> + FN(map_peek_elem),
>
> /* integer value in 'imm' field of BPF_CALL instruction selects which helper
> * function eBPF program intends to call
> diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
> index ff8262626b8f..4c2fa3ac56f6 100644
> --- a/kernel/bpf/Makefile
> +++ b/kernel/bpf/Makefile
> @@ -3,7 +3,7 @@ obj-y := core.o
>
> obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o
> obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o
> -obj-$(CONFIG_BPF_SYSCALL) += local_storage.o
> +obj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o
> obj-$(CONFIG_BPF_SYSCALL) += disasm.o
> obj-$(CONFIG_BPF_SYSCALL) += btf.o
> ifeq ($(CONFIG_NET),y)
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index defcf4df6d91..7c7eeea8cffc 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -1783,6 +1783,9 @@ BPF_CALL_0(bpf_user_rnd_u32)
> const struct bpf_func_proto bpf_map_lookup_elem_proto __weak;
> const struct bpf_func_proto bpf_map_update_elem_proto __weak;
> const struct bpf_func_proto bpf_map_delete_elem_proto __weak;
> +const struct bpf_func_proto bpf_map_push_elem_proto __weak;
> +const struct bpf_func_proto bpf_map_pop_elem_proto __weak;
> +const struct bpf_func_proto bpf_map_peek_elem_proto __weak;
>
> const struct bpf_func_proto bpf_get_prandom_u32_proto __weak;
> const struct bpf_func_proto bpf_get_smp_processor_id_proto __weak;
> diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
> index 6502115e8f55..ab0d5e3f9892 100644
> --- a/kernel/bpf/helpers.c
> +++ b/kernel/bpf/helpers.c
> @@ -76,6 +76,49 @@ const struct bpf_func_proto bpf_map_delete_elem_proto = {
> .arg2_type = ARG_PTR_TO_MAP_KEY,
> };
>
> +BPF_CALL_3(bpf_map_push_elem, struct bpf_map *, map, void *, value, u64, flags)
> +{
> + return map->ops->map_push_elem(map, value, flags);
> +}
> +
> +const struct bpf_func_proto bpf_map_push_elem_proto = {
> + .func = bpf_map_push_elem,
> + .gpl_only = false,
> + .pkt_access = true,
> + .ret_type = RET_INTEGER,
> + .arg1_type = ARG_CONST_MAP_PTR,
> + .arg2_type = ARG_PTR_TO_MAP_VALUE,
> + .arg3_type = ARG_ANYTHING,
> +};
> +
> +BPF_CALL_2(bpf_map_pop_elem, struct bpf_map *, map, void *, value)
> +{
> + return map->ops->map_pop_elem(map, value);
> +}
> +
> +const struct bpf_func_proto bpf_map_pop_elem_proto = {
> + .func = bpf_map_pop_elem,
> + .gpl_only = false,
> + .pkt_access = true,
> + .ret_type = RET_INTEGER,
> + .arg1_type = ARG_CONST_MAP_PTR,
> + .arg2_type = ARG_PTR_TO_UNINIT_MAP_VALUE,
> +};
> +
> +BPF_CALL_2(bpf_map_peek_elem, struct bpf_map *, map, void *, value)
> +{
> + return map->ops->map_peek_elem(map, value);
> +}
> +
> +const struct bpf_func_proto bpf_map_peek_elem_proto = {
> + .func = bpf_map_pop_elem,
> + .gpl_only = false,
> + .pkt_access = true,
> + .ret_type = RET_INTEGER,
> + .arg1_type = ARG_CONST_MAP_PTR,
> + .arg2_type = ARG_PTR_TO_UNINIT_MAP_VALUE,
> +};
> +
> const struct bpf_func_proto bpf_get_prandom_u32_proto = {
> .func = bpf_user_rnd_u32,
> .gpl_only = false,
> diff --git a/kernel/bpf/queue_stack_maps.c b/kernel/bpf/queue_stack_maps.c
> new file mode 100644
> index 000000000000..12a93fb37449
> --- /dev/null
> +++ b/kernel/bpf/queue_stack_maps.c
> @@ -0,0 +1,288 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * queue_stack_maps.c: BPF queue and stack maps
> + *
> + * Copyright (c) 2018 Politecnico di Torino
> + */
> +#include <linux/bpf.h>
> +#include <linux/list.h>
> +#include <linux/slab.h>
> +#include "percpu_freelist.h"
> +
> +#define QUEUE_STACK_CREATE_FLAG_MASK \
> + (BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY)
> +
> +
> +struct bpf_queue_stack {
> + struct bpf_map map;
> + raw_spinlock_t lock;
> + u32 head, tail;
> + u32 size; /* max_entries + 1 */
> +
> + char elements[0] __aligned(8);
> +};
> +
> +static struct bpf_queue_stack *bpf_queue_stack(struct bpf_map *map)
> +{
> + return container_of(map, struct bpf_queue_stack, map);
> +}
> +
> +static bool queue_stack_map_is_empty(struct bpf_queue_stack *qs)
> +{
> + return qs->head == qs->tail;
> +}
> +
> +static bool queue_stack_map_is_full(struct bpf_queue_stack *qs)
> +{
> + u32 head = qs->head + 1;
> +
> + if (unlikely(head >= qs->size))
> + head = 0;
> +
> + return head == qs->tail;
> +}
> +
> +/* Called from syscall */
> +static int queue_stack_map_alloc_check(union bpf_attr *attr)
> +{
> + /* check sanity of attributes */
> + if (attr->max_entries == 0 || attr->key_size != 0 ||
> + attr->map_flags & ~QUEUE_STACK_CREATE_FLAG_MASK)
> + return -EINVAL;
> +
> + if (attr->value_size > KMALLOC_MAX_SIZE)
> + /* if value_size is bigger, the user space won't be able to
> + * access the elements.
> + */
> + return -E2BIG;
> +
> + return 0;
> +}
> +
> +static struct bpf_map *queue_stack_map_alloc(union bpf_attr *attr)
> +{
> + int ret, numa_node = bpf_map_attr_numa_node(attr);
> + struct bpf_queue_stack *qs;
> + u32 size, value_size;
> + u64 queue_size, cost;
> +
> + size = attr->max_entries + 1;
> + value_size = attr->value_size;
> +
> + queue_size = sizeof(*qs) + (u64) value_size * size;
> +
> + cost = queue_size;
> + if (cost >= U32_MAX - PAGE_SIZE)
> + return ERR_PTR(-E2BIG);
> +
> + cost = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT;
> +
> + ret = bpf_map_precharge_memlock(cost);
> + if (ret < 0)
> + return ERR_PTR(ret);
> +
> + qs = bpf_map_area_alloc(queue_size, numa_node);
> + if (!qs)
> + return ERR_PTR(-ENOMEM);
> +
> + memset(qs, 0, sizeof(*qs));
> +
> + bpf_map_init_from_attr(&qs->map, attr);
> +
> + qs->map.pages = cost;
> + qs->size = size;
> +
> + raw_spin_lock_init(&qs->lock);
> +
> + return &qs->map;
> +}
> +
> +/* Called when map->refcnt goes to zero, either from workqueue or from syscall */
> +static void queue_stack_map_free(struct bpf_map *map)
> +{
> + struct bpf_queue_stack *qs = bpf_queue_stack(map);
> +
> + /* at this point bpf_prog->aux->refcnt == 0 and this map->refcnt == 0,
> + * so the programs (can be more than one that used this map) were
> + * disconnected from events. Wait for outstanding critical sections in
> + * these programs to complete
> + */
> + synchronize_rcu();
> +
> + bpf_map_area_free(qs);
> +}
> +
> +static int __queue_map_get(struct bpf_map *map, void *value, bool delete)
> +{
> + struct bpf_queue_stack *qs = bpf_queue_stack(map);
> + unsigned long flags;
> + int err = 0;
> + void *ptr;
> +
> + raw_spin_lock_irqsave(&qs->lock, flags);
> +
> + if (queue_stack_map_is_empty(qs)) {
> + err = -ENOENT;
> + goto out;
> + }
> +
> + ptr = &qs->elements[qs->tail * qs->map.value_size];
> + memcpy(value, ptr, qs->map.value_size);
> +
> + if (delete) {
> + if (unlikely(++qs->tail >= qs->size))
> + qs->tail = 0;
> + }
> +
> +out:
> + raw_spin_unlock_irqrestore(&qs->lock, flags);
> + return err;
> +}
> +
> +
> +static int __stack_map_get(struct bpf_map *map, void *value, bool delete)
> +{
> + struct bpf_queue_stack *qs = bpf_queue_stack(map);
> + unsigned long flags;
> + int err = 0;
> + void *ptr;
> + u32 index;
> +
> + raw_spin_lock_irqsave(&qs->lock, flags);
> +
> + if (queue_stack_map_is_empty(qs)) {
> + err = -ENOENT;
> + goto out;
> + }
> +
> + index = qs->head - 1;
> + if (unlikely(index >= qs->size))
> + index = qs->size - 1;
> +
> + ptr = &qs->elements[index * qs->map.value_size];
> + memcpy(value, ptr, qs->map.value_size);
> +
> + if (delete)
> + qs->head = index;
> +
> +out:
> + raw_spin_unlock_irqrestore(&qs->lock, flags);
> + return err;
> +}
> +
> +/* Called from syscall or from eBPF program */
> +static int queue_map_peek_elem(struct bpf_map *map, void *value)
> +{
> + return __queue_map_get(map, value, false);
> +}
> +
> +/* Called from syscall or from eBPF program */
> +static int stack_map_peek_elem(struct bpf_map *map, void *value)
> +{
> + return __stack_map_get(map, value, false);
> +}
> +
> +/* Called from syscall or from eBPF program */
> +static int queue_map_pop_elem(struct bpf_map *map, void *value)
> +{
> + return __queue_map_get(map, value, true);
> +}
> +
> +/* Called from syscall or from eBPF program */
> +static int stack_map_pop_elem(struct bpf_map *map, void *value)
> +{
> + return __stack_map_get(map, value, true);
> +}
> +
> +/* Called from syscall or from eBPF program */
> +static int queue_stack_map_push_elem(struct bpf_map *map, void *value,
> + u64 flags)
> +{
> + struct bpf_queue_stack *qs = bpf_queue_stack(map);
> + unsigned long irq_flags;
> + int err = 0;
> + void *dst;
> +
> + /* BPF_EXIST is used to force making room for a new element in case the
> + * map is full
> + */
> + bool replace = (flags & BPF_EXIST);
> +
> + /* Check supported flags for queue and stack maps */
> + if (flags & BPF_NOEXIST || flags > BPF_EXIST)
> + return -EINVAL;
> +
> + raw_spin_lock_irqsave(&qs->lock, irq_flags);
> +
> + if (queue_stack_map_is_full(qs)) {
> + if (!replace) {
> + err = -E2BIG;
> + goto out;
> + }
> + /* advance tail pointer to overwrite oldest element */
> + if (unlikely(++qs->tail >= qs->size))
> + qs->tail = 0;
> + }
> +
> + dst = &qs->elements[qs->head * qs->map.value_size];
> + memcpy(dst, value, qs->map.value_size);
> +
> + if (unlikely(++qs->head >= qs->size))
> + qs->head = 0;
> +
> +out:
> + raw_spin_unlock_irqrestore(&qs->lock, irq_flags);
> + return err;
> +}
> +
> +/* Called from syscall or from eBPF program */
> +static void *queue_stack_map_lookup_elem(struct bpf_map *map, void *key)
> +{
> + return NULL;
> +}
> +
> +/* Called from syscall or from eBPF program */
> +static int queue_stack_map_update_elem(struct bpf_map *map, void *key,
> + void *value, u64 flags)
> +{
> + return -EINVAL;
> +}
> +
> +/* Called from syscall or from eBPF program */
> +static int queue_stack_map_delete_elem(struct bpf_map *map, void *key)
> +{
> + return -EINVAL;
> +}
> +
> +/* Called from syscall */
> +static int queue_stack_map_get_next_key(struct bpf_map *map, void *key,
> + void *next_key)
> +{
> + return -EINVAL;
> +}
> +
> +const struct bpf_map_ops queue_map_ops = {
> + .map_alloc_check = queue_stack_map_alloc_check,
> + .map_alloc = queue_stack_map_alloc,
> + .map_free = queue_stack_map_free,
> + .map_lookup_elem = queue_stack_map_lookup_elem,
> + .map_update_elem = queue_stack_map_update_elem,
> + .map_delete_elem = queue_stack_map_delete_elem,
> + .map_push_elem = queue_stack_map_push_elem,
> + .map_pop_elem = queue_map_pop_elem,
> + .map_peek_elem = queue_map_peek_elem,
> + .map_get_next_key = queue_stack_map_get_next_key,
> +};
> +
> +const struct bpf_map_ops stack_map_ops = {
> + .map_alloc_check = queue_stack_map_alloc_check,
> + .map_alloc = queue_stack_map_alloc,
> + .map_free = queue_stack_map_free,
> + .map_lookup_elem = queue_stack_map_lookup_elem,
> + .map_update_elem = queue_stack_map_update_elem,
> + .map_delete_elem = queue_stack_map_delete_elem,
> + .map_push_elem = queue_stack_map_push_elem,
> + .map_pop_elem = stack_map_pop_elem,
> + .map_peek_elem = stack_map_peek_elem,
> + .map_get_next_key = queue_stack_map_get_next_key,
> +};
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index 78d9dd95e25f..1617407f9ee5 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -727,6 +727,9 @@ static int map_lookup_elem(union bpf_attr *attr)
> err = bpf_fd_htab_map_lookup_elem(map, key, value);
> } else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
> err = bpf_fd_reuseport_array_lookup_elem(map, key, value);
> + } else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
> + map->map_type == BPF_MAP_TYPE_STACK) {
> + err = map->ops->map_peek_elem(map, value);
> } else {
> rcu_read_lock();
> ptr = map->ops->map_lookup_elem(map, key);
> @@ -857,6 +860,9 @@ static int map_update_elem(union bpf_attr *attr)
> /* rcu_read_lock() is not needed */
> err = bpf_fd_reuseport_array_update_elem(map, key, value,
> attr->flags);
> + } else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
> + map->map_type == BPF_MAP_TYPE_STACK) {
> + err = map->ops->map_push_elem(map, value, attr->flags);
> } else {
> rcu_read_lock();
> err = map->ops->map_update_elem(map, key, value, attr->flags);
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index d84c91ac3b70..7d6d9cf9ebd5 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -2324,6 +2324,13 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env,
> if (func_id != BPF_FUNC_sk_select_reuseport)
> goto error;
> break;
> + case BPF_MAP_TYPE_QUEUE:
> + case BPF_MAP_TYPE_STACK:
> + if (func_id != BPF_FUNC_map_peek_elem &&
> + func_id != BPF_FUNC_map_pop_elem &&
> + func_id != BPF_FUNC_map_push_elem)
> + goto error;
> + break;
> default:
> break;
> }
> @@ -2380,6 +2387,13 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env,
> if (map->map_type != BPF_MAP_TYPE_REUSEPORT_SOCKARRAY)
> goto error;
> break;
> + case BPF_FUNC_map_peek_elem:
> + case BPF_FUNC_map_pop_elem:
> + case BPF_FUNC_map_push_elem:
> + if (map->map_type != BPF_MAP_TYPE_QUEUE &&
> + map->map_type != BPF_MAP_TYPE_STACK)
> + goto error;
> + break;
> default:
> break;
> }
> @@ -2675,7 +2689,10 @@ record_func_map(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
> if (func_id != BPF_FUNC_tail_call &&
> func_id != BPF_FUNC_map_lookup_elem &&
> func_id != BPF_FUNC_map_update_elem &&
> - func_id != BPF_FUNC_map_delete_elem)
> + func_id != BPF_FUNC_map_delete_elem &&
> + func_id != BPF_FUNC_map_push_elem &&
> + func_id != BPF_FUNC_map_pop_elem &&
> + func_id != BPF_FUNC_map_peek_elem)
> return 0;
>
> if (meta->map_ptr == NULL) {
> diff --git a/net/core/filter.c b/net/core/filter.c
> index 1a3ac6c46873..ea48ec789b5c 100644
> --- a/net/core/filter.c
> +++ b/net/core/filter.c
> @@ -4876,6 +4876,12 @@ bpf_base_func_proto(enum bpf_func_id func_id)
> return &bpf_map_update_elem_proto;
> case BPF_FUNC_map_delete_elem:
> return &bpf_map_delete_elem_proto;
> + case BPF_FUNC_map_push_elem:
> + return &bpf_map_push_elem_proto;
> + case BPF_FUNC_map_pop_elem:
> + return &bpf_map_pop_elem_proto;
> + case BPF_FUNC_map_peek_elem:
> + return &bpf_map_peek_elem_proto;
> case BPF_FUNC_get_prandom_u32:
> return &bpf_get_prandom_u32_proto;
> case BPF_FUNC_get_smp_processor_id:
>
^ permalink raw reply
* Re: [PATCH bpf-next v3 7/7] selftests/bpf: add test cases for queue and stack maps
From: Song Liu @ 2018-10-18 16:36 UTC (permalink / raw)
To: mauricio.vasquez; +Cc: Alexei Starovoitov, Daniel Borkmann, Networking
In-Reply-To: <153986860133.9127.6805806498868511760.stgit@kernel>
On Thu, Oct 18, 2018 at 6:16 AM Mauricio Vasquez B
<mauricio.vasquez@polito.it> wrote:
>
> test_maps:
> Tests that queue/stack maps are behaving correctly even in corner cases
>
> test_progs:
> Tests new ebpf helpers
>
> Signed-off-by: Mauricio Vasquez B <mauricio.vasquez@polito.it>
> ---
> tools/lib/bpf/bpf.c | 12 ++
> tools/lib/bpf/bpf.h | 2
> tools/testing/selftests/bpf/Makefile | 5 +
> tools/testing/selftests/bpf/bpf_helpers.h | 7 +
> tools/testing/selftests/bpf/test_maps.c | 122 ++++++++++++++++++++
> tools/testing/selftests/bpf/test_progs.c | 99 ++++++++++++++++
> tools/testing/selftests/bpf/test_queue_map.c | 4 +
> tools/testing/selftests/bpf/test_queue_stack_map.h | 59 ++++++++++
> tools/testing/selftests/bpf/test_stack_map.c | 4 +
> 9 files changed, 313 insertions(+), 1 deletion(-)
> create mode 100644 tools/testing/selftests/bpf/test_queue_map.c
> create mode 100644 tools/testing/selftests/bpf/test_queue_stack_map.h
> create mode 100644 tools/testing/selftests/bpf/test_stack_map.c
>
> diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> index d70a255cb05e..03f9bcc4ef50 100644
> --- a/tools/lib/bpf/bpf.c
> +++ b/tools/lib/bpf/bpf.c
> @@ -278,6 +278,18 @@ int bpf_map_lookup_elem(int fd, const void *key, void *value)
> return sys_bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
> }
>
> +int bpf_map_lookup_and_delete_elem(int fd, const void *key, void *value)
> +{
> + union bpf_attr attr;
> +
> + bzero(&attr, sizeof(attr));
> + attr.map_fd = fd;
> + attr.key = ptr_to_u64(key);
> + attr.value = ptr_to_u64(value);
> +
> + return sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr));
> +}
> +
> int bpf_map_delete_elem(int fd, const void *key)
> {
> union bpf_attr attr;
> diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
> index 258c3c178333..26a51538213c 100644
> --- a/tools/lib/bpf/bpf.h
> +++ b/tools/lib/bpf/bpf.h
> @@ -99,6 +99,8 @@ LIBBPF_API int bpf_map_update_elem(int fd, const void *key, const void *value,
> __u64 flags);
>
> LIBBPF_API int bpf_map_lookup_elem(int fd, const void *key, void *value);
> +LIBBPF_API int bpf_map_lookup_and_delete_elem(int fd, const void *key,
> + void *value);
> LIBBPF_API int bpf_map_delete_elem(int fd, const void *key);
> LIBBPF_API int bpf_map_get_next_key(int fd, const void *key, void *next_key);
> LIBBPF_API int bpf_obj_pin(int fd, const char *pathname);
> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> index d99dd6fc3fbe..e39dfb4e7970 100644
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
> @@ -37,7 +37,7 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test
> test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \
> get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \
> test_skb_cgroup_id_kern.o bpf_flow.o netcnt_prog.o \
> - test_sk_lookup_kern.o test_xdp_vlan.o
> + test_sk_lookup_kern.o test_xdp_vlan.o test_queue_map.o test_stack_map.o
>
> # Order correspond to 'make run_tests' order
> TEST_PROGS := test_kmod.sh \
> @@ -118,6 +118,9 @@ CLANG_FLAGS = -I. -I./include/uapi -I../../../include/uapi \
> $(OUTPUT)/test_l4lb_noinline.o: CLANG_FLAGS += -fno-inline
> $(OUTPUT)/test_xdp_noinline.o: CLANG_FLAGS += -fno-inline
>
> +$(OUTPUT)/test_queue_map.o: test_queue_stack_map.h
> +$(OUTPUT)/test_stack_map.o: test_queue_stack_map.h
This looks weird. You meant the .c files, right?
> +
> BTF_LLC_PROBE := $(shell $(LLC) -march=bpf -mattr=help 2>&1 | grep dwarfris)
> BTF_PAHOLE_PROBE := $(shell $(BTF_PAHOLE) --help 2>&1 | grep BTF)
> BTF_OBJCOPY_PROBE := $(shell $(LLVM_OBJCOPY) --help 2>&1 | grep -i 'usage.*llvm')
> diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h
> index fda8c162d0df..6407a3df0f3b 100644
> --- a/tools/testing/selftests/bpf/bpf_helpers.h
> +++ b/tools/testing/selftests/bpf/bpf_helpers.h
> @@ -16,6 +16,13 @@ static int (*bpf_map_update_elem)(void *map, void *key, void *value,
> (void *) BPF_FUNC_map_update_elem;
> static int (*bpf_map_delete_elem)(void *map, void *key) =
> (void *) BPF_FUNC_map_delete_elem;
> +static int (*bpf_map_push_elem)(void *map, void *value,
> + unsigned long long flags) =
> + (void *) BPF_FUNC_map_push_elem;
> +static int (*bpf_map_pop_elem)(void *map, void *value) =
> + (void *) BPF_FUNC_map_pop_elem;
> +static int (*bpf_map_peek_elem)(void *map, void *value) =
> + (void *) BPF_FUNC_map_peek_elem;
> static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) =
> (void *) BPF_FUNC_probe_read;
> static unsigned long long (*bpf_ktime_get_ns)(void) =
> diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c
> index 9b552c0fc47d..4db2116e52be 100644
> --- a/tools/testing/selftests/bpf/test_maps.c
> +++ b/tools/testing/selftests/bpf/test_maps.c
> @@ -15,6 +15,7 @@
> #include <string.h>
> #include <assert.h>
> #include <stdlib.h>
> +#include <time.h>
>
> #include <sys/wait.h>
> #include <sys/socket.h>
> @@ -471,6 +472,122 @@ static void test_devmap(int task, void *data)
> close(fd);
> }
>
> +static void test_queuemap(int task, void *data)
> +{
> + const int MAP_SIZE = 32;
> + __u32 vals[MAP_SIZE + MAP_SIZE/2], val;
> + int fd, i;
> +
> + /* Fill test values to be used */
> + for (i = 0; i < MAP_SIZE + MAP_SIZE/2; i++)
> + vals[i] = rand();
> +
> + /* Invalid key size */
> + fd = bpf_create_map(BPF_MAP_TYPE_QUEUE, 4, sizeof(val), MAP_SIZE,
> + map_flags);
> + assert(fd < 0 && errno == EINVAL);
> +
> + fd = bpf_create_map(BPF_MAP_TYPE_QUEUE, 0, sizeof(val), MAP_SIZE,
> + map_flags);
> + /* Queue map does not support BPF_F_NO_PREALLOC */
> + if (map_flags & BPF_F_NO_PREALLOC) {
> + assert(fd < 0 && errno == EINVAL);
> + return;
> + }
> + if (fd < 0) {
> + printf("Failed to create queuemap '%s'!\n", strerror(errno));
> + exit(1);
> + }
> +
> + /* Push MAP_SIZE elements */
> + for (i = 0; i < MAP_SIZE; i++)
> + assert(bpf_map_update_elem(fd, NULL, &vals[i], 0) == 0);
> +
> + /* Check that element cannot be pushed due to max_entries limit */
> + assert(bpf_map_update_elem(fd, NULL, &val, 0) == -1 &&
> + errno == E2BIG);
> +
> + /* Peek element */
> + assert(bpf_map_lookup_elem(fd, NULL, &val) == 0 && val == vals[0]);
> +
> + /* Replace half elements */
> + for (i = MAP_SIZE; i < MAP_SIZE + MAP_SIZE/2; i++)
> + assert(bpf_map_update_elem(fd, NULL, &vals[i], BPF_EXIST) == 0);
> +
> + /* Pop all elements */
> + for (i = MAP_SIZE/2; i < MAP_SIZE + MAP_SIZE/2; i++)
> + assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == 0 &&
> + val == vals[i]);
> +
> + /* Check that there are not elements left */
> + assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == -1 &&
> + errno == ENOENT);
> +
> + /* Check that non supported functions set errno to EINVAL */
> + assert(bpf_map_delete_elem(fd, NULL) == -1 && errno == EINVAL);
> + assert(bpf_map_get_next_key(fd, NULL, NULL) == -1 && errno == EINVAL);
> +
> + close(fd);
> +}
> +
> +static void test_stackmap(int task, void *data)
> +{
> + const int MAP_SIZE = 32;
> + __u32 vals[MAP_SIZE + MAP_SIZE/2], val;
> + int fd, i;
> +
> + /* Fill test values to be used */
> + for (i = 0; i < MAP_SIZE + MAP_SIZE/2; i++)
> + vals[i] = rand();
> +
> + /* Invalid key size */
> + fd = bpf_create_map(BPF_MAP_TYPE_STACK, 4, sizeof(val), MAP_SIZE,
> + map_flags);
> + assert(fd < 0 && errno == EINVAL);
> +
> + fd = bpf_create_map(BPF_MAP_TYPE_STACK, 0, sizeof(val), MAP_SIZE,
> + map_flags);
> + /* Stack map does not support BPF_F_NO_PREALLOC */
> + if (map_flags & BPF_F_NO_PREALLOC) {
> + assert(fd < 0 && errno == EINVAL);
> + return;
> + }
> + if (fd < 0) {
> + printf("Failed to create stackmap '%s'!\n", strerror(errno));
> + exit(1);
> + }
> +
> + /* Push MAP_SIZE elements */
> + for (i = 0; i < MAP_SIZE; i++)
> + assert(bpf_map_update_elem(fd, NULL, &vals[i], 0) == 0);
> +
> + /* Check that element cannot be pushed due to max_entries limit */
> + assert(bpf_map_update_elem(fd, NULL, &val, 0) == -1 &&
> + errno == E2BIG);
> +
> + /* Peek element */
> + assert(bpf_map_lookup_elem(fd, NULL, &val) == 0 && val == vals[i - 1]);
> +
> + /* Replace half elements */
> + for (i = MAP_SIZE; i < MAP_SIZE + MAP_SIZE/2; i++)
> + assert(bpf_map_update_elem(fd, NULL, &vals[i], BPF_EXIST) == 0);
> +
> + /* Pop all elements */
> + for (i = MAP_SIZE + MAP_SIZE/2 - 1; i >= MAP_SIZE/2; i--)
> + assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == 0 &&
> + val == vals[i]);
> +
> + /* Check that there are not elements left */
> + assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == -1 &&
> + errno == ENOENT);
> +
> + /* Check that non supported functions set errno to EINVAL */
> + assert(bpf_map_delete_elem(fd, NULL) == -1 && errno == EINVAL);
> + assert(bpf_map_get_next_key(fd, NULL, NULL) == -1 && errno == EINVAL);
> +
> + close(fd);
> +}
> +
> #include <sys/socket.h>
> #include <sys/ioctl.h>
> #include <arpa/inet.h>
> @@ -1434,10 +1551,15 @@ static void run_all_tests(void)
> test_map_wronly();
>
> test_reuseport_array();
> +
> + test_queuemap(0, NULL);
> + test_stackmap(0, NULL);
> }
>
> int main(void)
> {
> + srand(time(NULL));
> +
> map_flags = 0;
> run_all_tests();
>
> diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
> index e8becca9c521..2d3c04f45530 100644
> --- a/tools/testing/selftests/bpf/test_progs.c
> +++ b/tools/testing/selftests/bpf/test_progs.c
> @@ -1735,8 +1735,105 @@ static void test_reference_tracking()
> bpf_object__close(obj);
> }
>
> +enum {
> + QUEUE,
> + STACK,
> +};
> +
> +static void test_queue_stack_map(int type)
> +{
> + const int MAP_SIZE = 32;
> + __u32 vals[MAP_SIZE], duration, retval, size, val;
> + int i, err, prog_fd, map_in_fd, map_out_fd;
> + char file[32], buf[128];
> + struct bpf_object *obj;
> + struct iphdr *iph = (void *)buf + sizeof(struct ethhdr);
> +
> + /* Fill test values to be used */
> + for (i = 0; i < MAP_SIZE; i++)
> + vals[i] = rand();
> +
> + if (type == QUEUE)
> + strncpy(file, "./test_queue_map.o", sizeof(file));
> + else if (type == STACK)
> + strncpy(file, "./test_stack_map.o", sizeof(file));
> + else
> + return;
> +
> + err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
> + if (err) {
> + error_cnt++;
> + return;
> + }
> +
> + map_in_fd = bpf_find_map(__func__, obj, "map_in");
> + if (map_in_fd < 0)
> + goto out;
> +
> + map_out_fd = bpf_find_map(__func__, obj, "map_out");
> + if (map_out_fd < 0)
> + goto out;
> +
> + /* Push 32 elements to the input map */
> + for (i = 0; i < MAP_SIZE; i++) {
> + err = bpf_map_update_elem(map_in_fd, NULL, &vals[i], 0);
> + if (err) {
> + error_cnt++;
> + goto out;
> + }
> + }
> +
> + /* The eBPF program pushes iph.saddr in the output map,
> + * pops the input map and saves this value in iph.daddr
> + */
> + for (i = 0; i < MAP_SIZE; i++) {
> + if (type == QUEUE) {
> + val = vals[i];
> + pkt_v4.iph.saddr = vals[i] * 5;
> + } else if (type == STACK) {
> + val = vals[MAP_SIZE - 1 - i];
> + pkt_v4.iph.saddr = vals[MAP_SIZE - 1 - i] * 5;
> + }
> +
> + err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4),
> + buf, &size, &retval, &duration);
> + if (err || retval || size != sizeof(pkt_v4) ||
> + iph->daddr != val)
> + break;
> + }
> +
> + CHECK(err || retval || size != sizeof(pkt_v4) || iph->daddr != val,
> + "bpf_map_pop_elem",
> + "err %d errno %d retval %d size %d iph->daddr %u\n",
> + err, errno, retval, size, iph->daddr);
> +
> + /* Queue is empty, program should return TC_ACT_SHOT */
> + err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4),
> + buf, &size, &retval, &duration);
> + CHECK(err || retval != 2 /* TC_ACT_SHOT */|| size != sizeof(pkt_v4),
> + "check-queue-stack-map-empty",
> + "err %d errno %d retval %d size %d\n",
> + err, errno, retval, size);
> +
> + /* Check that the program pushed elements correctly */
> + for (i = 0; i < MAP_SIZE; i++) {
> + err = bpf_map_lookup_and_delete_elem(map_out_fd, NULL, &val);
> + if (err || val != vals[i] * 5)
> + break;
> + }
> +
> + CHECK(i != MAP_SIZE && (err || val != vals[i] * 5),
> + "bpf_map_push_elem", "err %d value %u\n", err, val);
> +
> +out:
> + pkt_v4.iph.saddr = 0;
> + bpf_object__close(obj);
> +}
> +
> int main(void)
> {
> + srand(time(NULL));
> +
> jit_enabled = is_jit_enabled();
>
> test_pkt_access();
> @@ -1757,6 +1854,8 @@ int main(void)
> test_task_fd_query_rawtp();
> test_task_fd_query_tp();
> test_reference_tracking();
> + test_queue_stack_map(QUEUE);
> + test_queue_stack_map(STACK);
>
> printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt);
> return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS;
> diff --git a/tools/testing/selftests/bpf/test_queue_map.c b/tools/testing/selftests/bpf/test_queue_map.c
> new file mode 100644
> index 000000000000..87db1f9da33d
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/test_queue_map.c
> @@ -0,0 +1,4 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2018 Politecnico di Torino
> +#define MAP_TYPE BPF_MAP_TYPE_QUEUE
> +#include "test_queue_stack_map.h"
> diff --git a/tools/testing/selftests/bpf/test_queue_stack_map.h b/tools/testing/selftests/bpf/test_queue_stack_map.h
> new file mode 100644
> index 000000000000..295b9b3bc5c7
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/test_queue_stack_map.h
> @@ -0,0 +1,59 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +// Copyright (c) 2018 Politecnico di Torino
> +#include <stddef.h>
> +#include <string.h>
> +#include <linux/bpf.h>
> +#include <linux/if_ether.h>
> +#include <linux/ip.h>
> +#include <linux/pkt_cls.h>
> +#include "bpf_helpers.h"
> +
> +int _version SEC("version") = 1;
> +
> +struct bpf_map_def __attribute__ ((section("maps"), used)) map_in = {
> + .type = MAP_TYPE,
> + .key_size = 0,
> + .value_size = sizeof(__u32),
> + .max_entries = 32,
> + .map_flags = 0,
> +};
> +
> +struct bpf_map_def __attribute__ ((section("maps"), used)) map_out = {
> + .type = MAP_TYPE,
> + .key_size = 0,
> + .value_size = sizeof(__u32),
> + .max_entries = 32,
> + .map_flags = 0,
> +};
> +
> +SEC("test")
> +int _test(struct __sk_buff *skb)
> +{
> + void *data_end = (void *)(long)skb->data_end;
> + void *data = (void *)(long)skb->data;
> + struct ethhdr *eth = (struct ethhdr *)(data);
> + __u32 value;
> + int err;
> +
> + if (eth + 1 > data_end)
> + return TC_ACT_SHOT;
> +
> + struct iphdr *iph = (struct iphdr *)(eth + 1);
> +
> + if (iph + 1 > data_end)
> + return TC_ACT_SHOT;
> +
> + err = bpf_map_pop_elem(&map_in, &value);
> + if (err)
> + return TC_ACT_SHOT;
> +
> + iph->daddr = value;
> +
> + err = bpf_map_push_elem(&map_out, &iph->saddr, 0);
> + if (err)
> + return TC_ACT_SHOT;
> +
> + return TC_ACT_OK;
> +}
> +
> +char _license[] SEC("license") = "GPL";
> diff --git a/tools/testing/selftests/bpf/test_stack_map.c b/tools/testing/selftests/bpf/test_stack_map.c
> new file mode 100644
> index 000000000000..31c3880e6da0
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/test_stack_map.c
> @@ -0,0 +1,4 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2018 Politecnico di Torino
> +#define MAP_TYPE BPF_MAP_TYPE_STACK
> +#include "test_queue_stack_map.h"
>
^ permalink raw reply
* Photos 36
From: Nancy @ 2018-10-18 11:38 UTC (permalink / raw)
To: netdev
We are an image team who can process 400+ images each day.
If you need any image editing service, please let us know.
Image cut out and clipping path, masking.
Such as for ecommerce photos, jewelry photos retouching, beauty and skin
images
and wedding photos.
We give test editing for your photos if you send us some.
Thanks,
Nancy
^ permalink raw reply
* Re: [PATCH v2] isdn: hfc_{pci,sx}: Avoid empty body if statements
From: Nathan Chancellor @ 2018-10-19 0:42 UTC (permalink / raw)
To: David Miller; +Cc: isdn, netdev, linux-kernel, yamada.masahiro
In-Reply-To: <20181018.172310.35380794084221855.davem@davemloft.net>
On Thu, Oct 18, 2018 at 05:23:10PM -0700, David Miller wrote:
> From: Nathan Chancellor <natechancellor@gmail.com>
> Date: Thu, 18 Oct 2018 17:21:17 -0700
>
> > Thanks for the review, I went ahead and compiled with the following diff
> > on top of v2 and got no warnings from Clang, GCC, or sparse, does this
> > seem satisfactory for v3?
>
> Well, one thing I notice.
>
> > @@ -86,7 +86,7 @@ release_io_hfcpci(struct IsdnCardState *cs)
> > pci_free_consistent(cs->hw.hfcpci.dev, 0x8000,
> > cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma);
> > cs->hw.hfcpci.fifos = NULL;
> > - iounmap((void *)cs->hw.hfcpci.pci_io);
> > + iounmap(cs->hw.hfcpci.pci_io);
> > }
>
> Driver uses iounmap().
>
> > @@ -1692,7 +1692,7 @@ setup_hfcpci(struct IsdnCard *card)
> > printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
> > return (0);
> > }
> > - cs->hw.hfcpci.pci_io = (char *)(unsigned long)dev_hfcpci->resource[1].start;
> > + cs->hw.hfcpci.pci_io = (void __iomem *)(unsigned long)dev_hfcpci->resource[1].start;
> > printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
>
> But does not use iomap(). You won't need any cast here if it did use
> iomap() properly.
>
> Thanks.
So this?
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 3dbaee8c604f..ea0e4c6de3fb 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -1692,7 +1692,7 @@ setup_hfcpci(struct IsdnCard *card)
printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
return (0);
}
- cs->hw.hfcpci.pci_io = (void __iomem *)(unsigned long)dev_hfcpci->resource[1].start;
+ cs->hw.hfcpci.pci_io = ioremap(dev_hfcpci->resource[1].start, 256);
printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
if (!cs->hw.hfcpci.pci_io) {
@@ -1716,7 +1716,6 @@ setup_hfcpci(struct IsdnCard *card)
return 0;
}
pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u32)cs->hw.hfcpci.dma);
- cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
printk(KERN_INFO
"HFC-PCI: defined at mem %p fifo %p(%lx) IRQ %d HZ %d\n",
cs->hw.hfcpci.pci_io,
Full context before the above diff should it be needed:
cs->hw.hfcpci.pci_io = (void *)(unsigned long)dev_hfcpci->resource[1].start;
printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
if (!cs->hw.hfcpci.pci_io) {
printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
return (0);
}
/* Allocate memory for FIFOS */
cs->hw.hfcpci.fifos = pci_alloc_consistent(cs->hw.hfcpci.dev,
0x8000, &cs->hw.hfcpci.dma);
if (!cs->hw.hfcpci.fifos) {
printk(KERN_WARNING "HFC-PCI: Error allocating FIFO memory!\n");
return 0;
}
if (cs->hw.hfcpci.dma & 0x7fff) {
printk(KERN_WARNING
"HFC-PCI: Error DMA memory not on 32K boundary (%lx)\n",
(u_long)cs->hw.hfcpci.dma);
pci_free_consistent(cs->hw.hfcpci.dev, 0x8000,
cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma);
return 0;
}
pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u32)cs->hw.hfcpci.dma);
cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
Thanks,
Nathan
^ permalink raw reply related
* Re: [PATCH bpf-next v2 02/13] bpf: btf: Add BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO
From: Edward Cree @ 2018-10-18 16:47 UTC (permalink / raw)
To: Martin Lau, Yonghong Song
Cc: Alexei Starovoitov, daniel@iogearbox.net, netdev@vger.kernel.org,
Kernel Team
In-Reply-To: <20181017175024.kugirxvpu2pymapk@kafai-mbp.dhcp.thefacebook.com>
On 17/10/18 18:50, Martin Lau wrote:
> On Wed, Oct 17, 2018 at 10:25:21AM -0700, Yonghong Song wrote:
>> What you stated is true, BTF_KIND_FUNC_PROTO corresponds to
>> dwarf subroutine tag which has no name while BTF_KIND_FUNC
>> must have a valid name. The original design is to have both
>> since they are corresponding to different dwarf constructs.
>>
>> Martin, what do you think?
> I prefer to have separate kinds. We need a way to distinguish them.
> For example, the BTF verifier is checking it. Having two kinds is
> cleaner instead of resorting to other hints from 'struct btf_type'.
> We don't lack of bits for kind.
But my point is that (a) they can be distinguished by how they are
used, and (b) the _only_ difference between them is how they are
used. In this C code:
int a = 5;
int foo(int x) { return a; }
int *b = &a;
int (*bar)(int) = &foo;
foo and *bar are _the same type_, just as a and *b are. It's just
that C has a slightly odd way of writing
int foo(int) = lambda x: a;
and foo itself is implicitly sorta-const.
What am I missing?
-Ed
^ permalink raw reply
* RE: [danielwa@cisco.com: Re: gianfar: Implement MAC reset and reconfig procedure]
From: Claudiu Manoil @ 2018-10-18 16:49 UTC (permalink / raw)
To: Daniel Walker; +Cc: Hemant Ramdasi, netdev@vger.kernel.org
In-Reply-To: <20181018140505.6q6bzx6uboqbimq6@zorba>
>-----Original Message-----
>From: Daniel Walker <danielwa@cisco.com>
>Sent: Thursday, October 18, 2018 5:05 PM
>To: Claudiu Manoil <claudiu.manoil@nxp.com>
>Cc: Hemant Ramdasi <hramdasi@cisco.com>; netdev@vger.kernel.org
>Subject: Re: [danielwa@cisco.com: Re: gianfar: Implement MAC reset and
>reconfig procedure]
>
[...]
>
>Here's some parts of the logs. I added a dump_stack() into adjust_link(). It
>does appear to be running, but it seems it's not working or not doing what you
>think it should be doing. The signature of the issue is below, you bring up the
>interface the first time and it works, then bring it down/up and no traffic.
>You can see in the second ping there is %100 packet loss.
>
>Seems the "Link is Up" lines indicate what adjust_link() changes.
>
>IPv6: ADDRCONF(NETDEV_UP): eth1: link is not ready
>CPU: 0 PID: 24 Comm: kworker/0:1 Not tainted 3.14.0-rc3 #174
>Workqueue: events_power_efficient phy_state_machine
>Call Trace:
>[e81ffdb0] [c0008718] show_stack+0xfc/0x1bc (unreliable)
>[e81ffe00] [c0602168] dump_stack+0x78/0xa0
>[e81ffe10] [c0437b20] adjust_link+0x30/0x2b0
>[e81ffe50] [c0430f1c] phy_state_machine+0x428/0x47c
>[e81ffe70] [c0060a84] process_one_work+0x158/0x3c4
>[e81ffea0] [c0061120] worker_thread+0x138/0x384
>[e81ffed0] [c0068714] kthread+0xd0/0xe4
>[e81fff40] [c0011bc8] ret_from_kernel_thread+0x5c/0x64
>CPU: 0 PID: 24 Comm: kworker/0:1 Not tainted 3.14.0-rc3 #174
>Workqueue: events_power_efficient phy_state_machine
>Call Trace:
>[e81ffdb0] [c0008718] show_stack+0xfc/0x1bc (unreliable)
>[e81ffe00] [c0602168] dump_stack+0x78/0xa0
>[e81ffe10] [c0437b20] adjust_link+0x30/0x2b0
>[e81ffe50] [c0430e60] phy_state_machine+0x36c/0x47c
>[e81ffe70] [c0060a84] process_one_work+0x158/0x3c4
>[e81ffea0] [c0061120] worker_thread+0x138/0x384
>[e81ffed0] [c0068714] kthread+0xd0/0xe4
>[e81fff40] [c0011bc8] ret_from_kernel_thread+0x5c/0x64
>fsl-gianfar ff725000.ethernet eth1: Link is Up - 100Mbps/Full - flow control off
>IPv6: ADDRCONF(NETDEV_CHANGE): eth1: link becomes ready
>PING 10.126.154.1 (10.126.154.1): 56 data bytes
>64 bytes from 10.126.154.1: seq=0 ttl=255 time=5.606 ms
>
>--- 10.126.154.1 ping statistics ---
>1 packets transmitted, 1 packets received, 0% packet loss
>round-trip min/avg/max = 5.606/5.606/5.606 ms
>CPU: 0 PID: 24 Comm: kworker/0:1 Not tainted 3.14.0-rc3 #174
>Workqueue: events_power_efficient phy_state_machine
>Call Trace:
>[e81ffdb0] [c0008718] show_stack+0xfc/0x1bc (unreliable)
>[e81ffe00] [c0602168] dump_stack+0x78/0xa0
>[e81ffe10] [c0437b20] adjust_link+0x30/0x2b0
>[e81ffe50] [c0430f1c] phy_state_machine+0x428/0x47c
>[e81ffe70] [c0060a84] process_one_work+0x158/0x3c4
>[e81ffea0] [c0061120] worker_thread+0x138/0x384
>[e81ffed0] [c0068714] kthread+0xd0/0xe4
>[e81fff40] [c0011bc8] ret_from_kernel_thread+0x5c/0x64
>CPU: 0 PID: 24 Comm: kworker/0:1 Not tainted 3.14.0-rc3 #174
>Workqueue: events_power_efficient phy_state_machine
>Call Trace:
>[e81ffdb0] [c0008718] show_stack+0xfc/0x1bc (unreliable)
>[e81ffe00] [c0602168] dump_stack+0x78/0xa0
>[e81ffe10] [c0437b20] adjust_link+0x30/0x2b0
>[e81ffe50] [c0430e60] phy_state_machine+0x36c/0x47c
>[e81ffe70] [c0060a84] process_one_work+0x158/0x3c4
>[e81ffea0] [c0061120] worker_thread+0x138/0x384
>[e81ffed0] [c0068714] kthread+0xd0/0xe4
>[e81fff40] [c0011bc8] ret_from_kernel_thread+0x5c/0x64
>fsl-gianfar ff725000.ethernet eth1: Link is Up - 100Mbps/Full - flow control off
>PING 10.126.154.1 (10.126.154.1): 56 data bytes
>
>--- 10.126.154.1 ping statistics ---
>1 packets transmitted, 0 packets received, 100% packet loss
I can only advise you to check whether the MACCFG2 register settings are consistent
at this point, when ping fails. You should check the I/F Mode bits (22-23) and the
Full Duplex bit (31), in big-endian format. If these do not match the 100Mbps full
duplex link mode, then it might be that another thread (probably doing reset_gfar)
changes MACCFG2 concurrently. I think MACCFG2 may be dumped with ethtool -d.
I can get my hands on a board no sooner than maybe next week.
-Claudiu
^ permalink raw reply
* Re: pull request (net): ipsec 2018-10-18
From: David Miller @ 2018-10-18 16:56 UTC (permalink / raw)
To: steffen.klassert; +Cc: herbert, netdev
In-Reply-To: <20181018102521.24997-1-steffen.klassert@secunet.com>
From: Steffen Klassert <steffen.klassert@secunet.com>
Date: Thu, 18 Oct 2018 12:25:17 +0200
> 1) Free the xfrm interface gro_cells when deleting the
> interface, otherwise we leak it. From Li RongQing.
>
> 2) net/core/flow.c does not exist anymore, so remove it
> from the MAINTAINERS file.
>
> 3) Fix a slab-out-of-bounds in _decode_session6.
> From Alexei Starovoitov.
>
> 4) Fix RCU protection when policies inserted into
> thei bydst lists. From Florian Westphal.
>
> Please pull or let me know if there are problems.
Pulled, thank you!
^ permalink raw reply
* Re: pull request (net-next): ipsec-next 2018-10-18
From: David Miller @ 2018-10-18 16:58 UTC (permalink / raw)
To: steffen.klassert; +Cc: herbert, netdev
In-Reply-To: <20181018105654.32149-1-steffen.klassert@secunet.com>
From: Steffen Klassert <steffen.klassert@secunet.com>
Date: Thu, 18 Oct 2018 12:56:51 +0200
> 1) Remove an unnecessary dev->tstats check in xfrmi_get_stats64.
> From Li RongQing.
>
> 2) We currently do a sizeof(element) instead of a sizeof(array)
> check when initializing the ovec array of the secpath.
> Currently this array can have only one element, so code is
> OK but error-prone. Change this to do a sizeof(array)
> check so that we can add more elements in future.
> From Li RongQing.
>
> 3) Improve xfrm IPv6 address hashing by using the complete IPv6
> addresses for a hash. From Michal Kubecek.
>
> Please pull or let me know if there are problems.
Also pulled, thank you.
^ permalink raw reply
* Re: [PATCH v2] isdn: hfc_{pci,sx}: Avoid empty body if statements
From: Nathan Chancellor @ 2018-10-19 1:01 UTC (permalink / raw)
To: David Miller; +Cc: isdn, netdev, linux-kernel, yamada.masahiro
In-Reply-To: <20181018.175058.827953425036498775.davem@davemloft.net>
On Thu, Oct 18, 2018 at 05:50:58PM -0700, David Miller wrote:
> From: Nathan Chancellor <natechancellor@gmail.com>
> Date: Thu, 18 Oct 2018 17:42:51 -0700
>
> > On Thu, Oct 18, 2018 at 05:23:10PM -0700, David Miller wrote:
> >> From: Nathan Chancellor <natechancellor@gmail.com>
> >> Date: Thu, 18 Oct 2018 17:21:17 -0700
> >>
> >> > Thanks for the review, I went ahead and compiled with the following diff
> >> > on top of v2 and got no warnings from Clang, GCC, or sparse, does this
> >> > seem satisfactory for v3?
> >>
> >> Well, one thing I notice.
> >>
> >
> >> > @@ -86,7 +86,7 @@ release_io_hfcpci(struct IsdnCardState *cs)
> >> > pci_free_consistent(cs->hw.hfcpci.dev, 0x8000,
> >> > cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma);
> >> > cs->hw.hfcpci.fifos = NULL;
> >> > - iounmap((void *)cs->hw.hfcpci.pci_io);
> >> > + iounmap(cs->hw.hfcpci.pci_io);
> >> > }
> >>
> >> Driver uses iounmap().
> >>
> >> > @@ -1692,7 +1692,7 @@ setup_hfcpci(struct IsdnCard *card)
> >> > printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
> >> > return (0);
> >> > }
> >> > - cs->hw.hfcpci.pci_io = (char *)(unsigned long)dev_hfcpci->resource[1].start;
> >> > + cs->hw.hfcpci.pci_io = (void __iomem *)(unsigned long)dev_hfcpci->resource[1].start;
> >> > printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
> >>
> >> But does not use iomap(). You won't need any cast here if it did use
> >> iomap() properly.
> >>
> >> Thanks.
> >
> > So this?
>
> That's definitely a lot better, yes!
>
> I wonder what exactly it is checking there though. I guess it wants to see if the
> resource->start value is zero and bail with an error it so.
>
> Anyways, this code has been like this for ages and what you are proposing is
> definitely a significant improvement.
>
> Thanks.
I was thinking the same thing. I think ioremap will still error out if
start is zero so this should be fine. I'll roll all of this up into v3,
thanks a lot for the review!
Nathan
^ permalink raw reply
* Re: [PATCH net-next] netpoll: allow cleanup to be synchronous
From: Neil Horman @ 2018-10-18 16:59 UTC (permalink / raw)
To: Banerjee, Debabrata; +Cc: David Miller, netdev@vger.kernel.org
In-Reply-To: <5777390a08cb43709615237dcd4ada83@usma1ex-dag1mb2.msg.corp.akamai.com>
On Thu, Oct 18, 2018 at 03:17:06PM +0000, Banerjee, Debabrata wrote:
> > From: Neil Horman <nhorman@tuxdriver.com>
>
> > Agreed, this doesn't make sense. If you want a synchronous cleanup, create
> > a wrapper function that creates a wait queue, calls __netpoll_free_async,
> > and blocks on the wait queue completion. Modify the cleanup_work
> > method(s) to complete the wait queue, and you've got what you want.
> >
> > Neil
>
> Actually the patch looks bad, but it seems to turn out the rtnl is always
> held by the parent when it is called, and asynchronous cleanup doesn't
> seem to be necessary at all. Perhaps you could share your deadlock
> test case for 2cde6acd49da?
>
That commit doesn't fix a deadlock, it fixes a modification of data that must
only be modified under the protection of the rtnl lock. From the commit log:
__netpoll_rcu_free is used to free netpoll structures when the rtnl_lock is
already held. The mechanism is used to asynchronously call __netpoll_cleanup
outside of the holding of the rtnl_lock, so as to avoid deadlock.
Unfortunately, __netpoll_cleanup modifies pointers (dev->np), which means the
rtnl_lock must be held while calling it. Further, it cannot be held, because
rcu callbacks may be issued in softirq contexts, which cannot sleep.
"The mechanism" is referring to the use of rcu callbacks, which origionally were
put in place to allow the freeing of data outside the holding of the rtnl, which
did avoid deadlock.
This patch fixes the fact that __netpoll_cleanup modifies the dev->np pointer
outside of the rtnl_lock, which is disallowed because readers of dev->np assume
it will be stable while rtnl is held.
As for the workqueue not being needed anymore, it definately used to be, but it
appears that most of the instances where a deadlock might occur have been
modified such that it is no longer the case. The team driver still seems to be
an outlier there though I think , in that it doesn't guarantee the holding of
rtnl in its port add/delete paths.
It might be worth cleaning that up and simply replacing all the calls to
__netpoll_free_async with direct calls to __netpoll_cleanup. That would let you
eliminate the former function alltogether.
Neil
> Patch v2 coming next.
>
> -Deb
>
^ permalink raw reply
* Re: [PATCH v3 lora-next 1/5] regmap: Add regmap_noinc_write API
From: Andreas Färber @ 2018-10-18 16:59 UTC (permalink / raw)
To: Ben Whitten, Mark Brown
Cc: starnight, hasnain.virk, netdev, liuxuenetmail, shess,
Ben Whitten, Greg Kroah-Hartman, Rafael J. Wysocki, linux-kernel,
Stefan Rehm, linux-spi@vger.kernel.org
In-Reply-To: <1539361567-3602-2-git-send-email-ben.whitten@lairdtech.com>
Am 12.10.18 um 18:26 schrieb Ben Whitten:
> The regmap API had a noinc_read function added for instances where devices
> supported returning data from an internal FIFO in a single read.
>
> This commit adds the noinc_write variant to allow writing to a non
> incrementing register, this is used in devices such as the sx1301 for
> loading firmware.
>
> Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
Reviewed-by: Andreas Färber <afaerber@suse.de>
Mark, please take this one through your tree - I'll rebase the LoRa
parts on linux-next then.
Thanks,
Andreas
> ---
> drivers/base/regmap/internal.h | 3 ++
> drivers/base/regmap/regmap.c | 77 ++++++++++++++++++++++++++++++++++++++++++
> include/linux/regmap.h | 19 +++++++++++
> 3 files changed, 99 insertions(+)
>
> diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
> index a6bf34d63..404f123 100644
> --- a/drivers/base/regmap/internal.h
> +++ b/drivers/base/regmap/internal.h
> @@ -94,11 +94,13 @@ struct regmap {
> bool (*readable_reg)(struct device *dev, unsigned int reg);
> bool (*volatile_reg)(struct device *dev, unsigned int reg);
> bool (*precious_reg)(struct device *dev, unsigned int reg);
> + bool (*writeable_noinc_reg)(struct device *dev, unsigned int reg);
> bool (*readable_noinc_reg)(struct device *dev, unsigned int reg);
> const struct regmap_access_table *wr_table;
> const struct regmap_access_table *rd_table;
> const struct regmap_access_table *volatile_table;
> const struct regmap_access_table *precious_table;
> + const struct regmap_access_table *wr_noinc_table;
> const struct regmap_access_table *rd_noinc_table;
>
> int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
> @@ -183,6 +185,7 @@ bool regmap_writeable(struct regmap *map, unsigned int reg);
> bool regmap_readable(struct regmap *map, unsigned int reg);
> bool regmap_volatile(struct regmap *map, unsigned int reg);
> bool regmap_precious(struct regmap *map, unsigned int reg);
> +bool regmap_writeable_noinc(struct regmap *map, unsigned int reg);
> bool regmap_readable_noinc(struct regmap *map, unsigned int reg);
>
> int _regmap_write(struct regmap *map, unsigned int reg,
> diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
> index 0360a90..d4f1fc6 100644
> --- a/drivers/base/regmap/regmap.c
> +++ b/drivers/base/regmap/regmap.c
> @@ -168,6 +168,17 @@ bool regmap_precious(struct regmap *map, unsigned int reg)
> return false;
> }
>
> +bool regmap_writeable_noinc(struct regmap *map, unsigned int reg)
> +{
> + if (map->writeable_noinc_reg)
> + return map->writeable_noinc_reg(map->dev, reg);
> +
> + if (map->wr_noinc_table)
> + return regmap_check_range_table(map, reg, map->wr_noinc_table);
> +
> + return true;
> +}
> +
> bool regmap_readable_noinc(struct regmap *map, unsigned int reg)
> {
> if (map->readable_noinc_reg)
> @@ -777,11 +788,13 @@ struct regmap *__regmap_init(struct device *dev,
> map->rd_table = config->rd_table;
> map->volatile_table = config->volatile_table;
> map->precious_table = config->precious_table;
> + map->wr_noinc_table = config->wr_noinc_table;
> map->rd_noinc_table = config->rd_noinc_table;
> map->writeable_reg = config->writeable_reg;
> map->readable_reg = config->readable_reg;
> map->volatile_reg = config->volatile_reg;
> map->precious_reg = config->precious_reg;
> + map->writeable_noinc_reg = config->writeable_noinc_reg;
> map->readable_noinc_reg = config->readable_noinc_reg;
> map->cache_type = config->cache_type;
>
> @@ -1298,6 +1311,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
> map->readable_reg = config->readable_reg;
> map->volatile_reg = config->volatile_reg;
> map->precious_reg = config->precious_reg;
> + map->writeable_noinc_reg = config->writeable_noinc_reg;
> map->readable_noinc_reg = config->readable_noinc_reg;
> map->cache_type = config->cache_type;
>
> @@ -1898,6 +1912,69 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
> EXPORT_SYMBOL_GPL(regmap_raw_write);
>
> /**
> + * regmap_noinc_write(): Write data from a register without incrementing the
> + * register number
> + *
> + * @map: Register map to write to
> + * @reg: Register to write to
> + * @val: Pointer to data buffer
> + * @val_len: Length of output buffer in bytes.
> + *
> + * The regmap API usually assumes that bulk bus write operations will write a
> + * range of registers. Some devices have certain registers for which a write
> + * operation can write to an internal FIFO.
> + *
> + * The target register must be volatile but registers after it can be
> + * completely unrelated cacheable registers.
> + *
> + * This will attempt multiple writes as required to write val_len bytes.
> + *
> + * A value of zero will be returned on success, a negative errno will be
> + * returned in error cases.
> + */
> +int regmap_noinc_write(struct regmap *map, unsigned int reg,
> + const void *val, size_t val_len)
> +{
> + size_t write_len;
> + int ret;
> +
> + if (!map->bus)
> + return -EINVAL;
> + if (!map->bus->write)
> + return -ENOTSUPP;
> + if (val_len % map->format.val_bytes)
> + return -EINVAL;
> + if (!IS_ALIGNED(reg, map->reg_stride))
> + return -EINVAL;
> + if (val_len == 0)
> + return -EINVAL;
> +
> + map->lock(map->lock_arg);
> +
> + if (!regmap_volatile(map, reg) || !regmap_writeable_noinc(map, reg)) {
> + ret = -EINVAL;
> + goto out_unlock;
> + }
> +
> + while (val_len) {
> + if (map->max_raw_write && map->max_raw_write < val_len)
> + write_len = map->max_raw_write;
> + else
> + write_len = val_len;
> + ret = _regmap_raw_write(map, reg, val, write_len);
> + if (ret)
> + goto out_unlock;
> + val = ((u8 *)val) + write_len;
> + val_len -= write_len;
> + }
> +
> +out_unlock:
> + map->unlock(map->lock_arg);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(regmap_noinc_write);
> +
> +/**
> * regmap_field_update_bits_base() - Perform a read/modify/write cycle a
> * register field.
> *
> diff --git a/include/linux/regmap.h b/include/linux/regmap.h
> index 379505a..de04dc4 100644
> --- a/include/linux/regmap.h
> +++ b/include/linux/regmap.h
> @@ -268,6 +268,13 @@ typedef void (*regmap_unlock)(void *);
> * field is NULL but precious_table (see below) is not, the
> * check is performed on such table (a register is precious if
> * it belongs to one of the ranges specified by precious_table).
> + * @writeable_noinc_reg: Optional callback returning true if the register
> + * supports multiple write operations without incrementing
> + * the register number. If this field is NULL but
> + * wr_noinc_table (see below) is not, the check is
> + * performed on such table (a register is no increment
> + * writeable if it belongs to one of the ranges specified
> + * by wr_noinc_table).
> * @readable_noinc_reg: Optional callback returning true if the register
> * supports multiple read operations without incrementing
> * the register number. If this field is NULL but
> @@ -302,6 +309,7 @@ typedef void (*regmap_unlock)(void *);
> * @rd_table: As above, for read access.
> * @volatile_table: As above, for volatile registers.
> * @precious_table: As above, for precious registers.
> + * @wr_noinc_table: As above, for no increment writeable registers.
> * @rd_noinc_table: As above, for no increment readable registers.
> * @reg_defaults: Power on reset values for registers (for use with
> * register cache support).
> @@ -352,6 +360,7 @@ struct regmap_config {
> bool (*readable_reg)(struct device *dev, unsigned int reg);
> bool (*volatile_reg)(struct device *dev, unsigned int reg);
> bool (*precious_reg)(struct device *dev, unsigned int reg);
> + bool (*writeable_noinc_reg)(struct device *dev, unsigned int reg);
> bool (*readable_noinc_reg)(struct device *dev, unsigned int reg);
>
> bool disable_locking;
> @@ -369,6 +378,7 @@ struct regmap_config {
> const struct regmap_access_table *rd_table;
> const struct regmap_access_table *volatile_table;
> const struct regmap_access_table *precious_table;
> + const struct regmap_access_table *wr_noinc_table;
> const struct regmap_access_table *rd_noinc_table;
> const struct reg_default *reg_defaults;
> unsigned int num_reg_defaults;
> @@ -979,6 +989,8 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);
> int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val);
> int regmap_raw_write(struct regmap *map, unsigned int reg,
> const void *val, size_t val_len);
> +int regmap_noinc_write(struct regmap *map, unsigned int reg,
> + const void *val, size_t val_len);
> int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
> size_t val_count);
> int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs,
> @@ -1222,6 +1234,13 @@ static inline int regmap_raw_write_async(struct regmap *map, unsigned int reg,
> return -EINVAL;
> }
>
> +static inline int regmap_noinc_write(struct regmap *map, unsigned int reg,
> + const void *val, size_t val_len)
> +{
> + WARN_ONCE(1, "regmap API is disabled");
> + return -EINVAL;
> +}
> +
> static inline int regmap_bulk_write(struct regmap *map, unsigned int reg,
> const void *val, size_t val_count)
> {
>
--
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
^ permalink raw reply
* [PATCH v3] isdn: hfc_{pci,sx}: Avoid empty body if statements
From: Nathan Chancellor @ 2018-10-19 1:11 UTC (permalink / raw)
To: Karsten Keil, David S. Miller
Cc: netdev, linux-kernel, Masahiro Yamada, Nathan Chancellor
In-Reply-To: <20181018034935.16819-1-natechancellor@gmail.com>
Clang warns:
drivers/isdn/hisax/hfc_pci.c:131:34: error: if statement has empty body
[-Werror,-Wempty-body]
if (Read_hfc(cs, HFCPCI_INT_S1));
^
drivers/isdn/hisax/hfc_pci.c:131:34: note: put the semicolon on a
separate line to silence this warning
In my attempt to hide the warnings because I thought they didn't serve
any purpose[1], Masahiro Yamada pointed out that {Read,Write}_hfc in
hci_pci.c should be using a standard register access method; otherwise,
the compiler will just remove the if statements.
For hfc_pci, use the versions of {Read,Write}_hfc found in
drivers/isdn/hardware/mISDN/hfc_pCI.h while converting pci_io to be
'void __iomem *' (and clean up ioremap) then remove the empty if
statements.
For hfc_sx, {Read,Write}_hfc are already use a proper register accessor
(inb, outb) so just remove the unnecessary if statements.
[1]: https://lore.kernel.org/lkml/20181016021454.11953-1-natechancellor@gmail.com/
Link: https://github.com/ClangBuiltLinux/linux/issues/66
Suggested-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Signed-off-by: Nathan Chancellor <natechancellor@gmail.com>
---
v1 -> v2:
* Remove unnecessary cast to void, just remove if statements (thanks to
review from Masahiro).
* Clean up commit message.
v2 -> v3:
* Convert hfc_pci to properly use readb/writeb to avoid static checker
issues.
drivers/isdn/hisax/hfc_pci.c | 11 +++++------
drivers/isdn/hisax/hfc_pci.h | 4 ++--
drivers/isdn/hisax/hfc_sx.c | 6 +++---
drivers/isdn/hisax/hisax.h | 2 +-
4 files changed, 11 insertions(+), 12 deletions(-)
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 8e5b03161b2f..ea0e4c6de3fb 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -86,7 +86,7 @@ release_io_hfcpci(struct IsdnCardState *cs)
pci_free_consistent(cs->hw.hfcpci.dev, 0x8000,
cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma);
cs->hw.hfcpci.fifos = NULL;
- iounmap((void *)cs->hw.hfcpci.pci_io);
+ iounmap(cs->hw.hfcpci.pci_io);
}
/********************************************************************************/
@@ -128,7 +128,7 @@ reset_hfcpci(struct IsdnCardState *cs)
Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
/* Clear already pending ints */
- if (Read_hfc(cs, HFCPCI_INT_S1));
+ Read_hfc(cs, HFCPCI_INT_S1);
Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 2); /* HFC ST 2 */
udelay(10);
@@ -158,7 +158,7 @@ reset_hfcpci(struct IsdnCardState *cs)
/* Finally enable IRQ output */
cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE;
Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
- if (Read_hfc(cs, HFCPCI_INT_S1));
+ Read_hfc(cs, HFCPCI_INT_S1);
}
/***************************************************/
@@ -1537,7 +1537,7 @@ hfcpci_bh(struct work_struct *work)
cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
/* Clear already pending ints */
- if (Read_hfc(cs, HFCPCI_INT_S1));
+ Read_hfc(cs, HFCPCI_INT_S1);
Write_hfc(cs, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
udelay(10);
Write_hfc(cs, HFCPCI_STATES, 4);
@@ -1692,7 +1692,7 @@ setup_hfcpci(struct IsdnCard *card)
printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
return (0);
}
- cs->hw.hfcpci.pci_io = (char *)(unsigned long)dev_hfcpci->resource[1].start;
+ cs->hw.hfcpci.pci_io = ioremap(dev_hfcpci->resource[1].start, 256);
printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
if (!cs->hw.hfcpci.pci_io) {
@@ -1716,7 +1716,6 @@ setup_hfcpci(struct IsdnCard *card)
return 0;
}
pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u32)cs->hw.hfcpci.dma);
- cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
printk(KERN_INFO
"HFC-PCI: defined at mem %p fifo %p(%lx) IRQ %d HZ %d\n",
cs->hw.hfcpci.pci_io,
diff --git a/drivers/isdn/hisax/hfc_pci.h b/drivers/isdn/hisax/hfc_pci.h
index 4e58700a3e61..4c3b3ba35726 100644
--- a/drivers/isdn/hisax/hfc_pci.h
+++ b/drivers/isdn/hisax/hfc_pci.h
@@ -228,8 +228,8 @@ typedef union {
} fifo_area;
-#define Write_hfc(a, b, c) (*(((u_char *)a->hw.hfcpci.pci_io) + b) = c)
-#define Read_hfc(a, b) (*(((u_char *)a->hw.hfcpci.pci_io) + b))
+#define Write_hfc(a, b, c) (writeb(c, (a->hw.hfcpci.pci_io) + b))
+#define Read_hfc(a, b) (readb((a->hw.hfcpci.pci_io) + b))
extern void main_irq_hcpci(struct BCState *bcs);
extern void releasehfcpci(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index 4d3b4b2f2612..12af628d9b2c 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -381,7 +381,7 @@ reset_hfcsx(struct IsdnCardState *cs)
Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
/* Clear already pending ints */
- if (Read_hfc(cs, HFCSX_INT_S1));
+ Read_hfc(cs, HFCSX_INT_S1);
Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 2); /* HFC ST 2 */
udelay(10);
@@ -411,7 +411,7 @@ reset_hfcsx(struct IsdnCardState *cs)
/* Finally enable IRQ output */
cs->hw.hfcsx.int_m2 = HFCSX_IRQ_ENABLE;
Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
- if (Read_hfc(cs, HFCSX_INT_S2));
+ Read_hfc(cs, HFCSX_INT_S2);
}
/***************************************************/
@@ -1288,7 +1288,7 @@ hfcsx_bh(struct work_struct *work)
cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
/* Clear already pending ints */
- if (Read_hfc(cs, HFCSX_INT_S1));
+ Read_hfc(cs, HFCSX_INT_S1);
Write_hfc(cs, HFCSX_STATES, 4 | HFCSX_LOAD_STATE);
udelay(10);
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 338d0408b377..40080e06421c 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -703,7 +703,7 @@ struct hfcPCI_hw {
unsigned char nt_mode;
int nt_timer;
struct pci_dev *dev;
- unsigned char *pci_io; /* start of PCI IO memory */
+ void __iomem *pci_io; /* start of PCI IO memory */
dma_addr_t dma; /* dma handle for Fifos */
void *fifos; /* FIFO memory */
int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */
--
2.19.1
^ permalink raw reply related
* Re: [danielwa@cisco.com: Re: gianfar: Implement MAC reset and reconfig procedure]
From: Daniel Walker @ 2018-10-18 17:11 UTC (permalink / raw)
To: Claudiu Manoil; +Cc: Hemant Ramdasi, netdev@vger.kernel.org
In-Reply-To: <HE1PR04MB1145DAA9F214275D6489B06B96F80@HE1PR04MB1145.eurprd04.prod.outlook.com>
On Thu, Oct 18, 2018 at 04:49:26PM +0000, Claudiu Manoil wrote:
> I can only advise you to check whether the MACCFG2 register settings are consistent
> at this point, when ping fails. You should check the I/F Mode bits (22-23) and the
> Full Duplex bit (31), in big-endian format. If these do not match the 100Mbps full
> duplex link mode, then it might be that another thread (probably doing reset_gfar)
> changes MACCFG2 concurrently. I think MACCFG2 may be dumped with ethtool -d.
> I can get my hands on a board no sooner than maybe next week.
A board won't help you .. I'm running on customer hardware which you don't have
access to.
After boot up you have MACCFG2 = 0x7205 which is the same
as the INIT settings.
After the interface is brought up adjust_link() changes to MACCFG2 = 0x7105
which I think is MII.
0x7105 stays after the interface is brought down until gfar_mac_reset sets it to
0x7205 (GMII) .. then adjust link resets it to 0x7105 (MII) ..
That goes on and on each time to interface is brought down/up. It seems like
this is what your expecting to happen, but it doesn't seems to work %100 of the
time.
Daniel
^ 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