* Re: [PATCH 04/40] proc: introduce proc_create_seq{,_data}
From: David Howells @ 2018-04-30 13:19 UTC (permalink / raw)
To: Christoph Hellwig
Cc: linux-rtc, Alessandro Zummo, Alexandre Belloni, devel, linux-scsi,
linux-acpi, Greg Kroah-Hartman, Jiri Slaby, megaraidlinux.pdl,
linux-kernel, Alexey Dobriyan, dhowells, linux-ide,
netfilter-devel, Alexander Viro, netdev, Andrew Morton,
linux-ext4, linux-afs, jfs-discussion, drbd-dev
In-Reply-To: <20180425154827.32251-5-hch@lst.de>
Christoph Hellwig <hch@lst.de> wrote:
> +
> +struct proc_dir_entry *proc_create_seq_data(const char *name, umode_t mode,
> + struct proc_dir_entry *parent, const struct seq_operations *ops,
> + void *data)
> +{
> ...
> +EXPORT_SYMBOL(proc_create_seq_data);
Please add documentation comments to exported functions when you add them.
David
^ permalink raw reply
* Re: [PATCH] net: phy: marvell: clear wol event before setting it
From: Andrew Lunn @ 2018-04-30 13:17 UTC (permalink / raw)
To: Jisheng Zhang
Cc: Bhadram Varka, Florian Fainelli, David S. Miller, netdev,
linux-kernel, Jingju Hou
In-Reply-To: <20180427152555.5e8efb9c@xhacker.debian>
> > diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
> > index ed8a67d..5d3d138 100644
> > --- a/drivers/net/phy/marvell.c
> > +++ b/drivers/net/phy/marvell.c
> > @@ -55,6 +55,7 @@
> >
> > #define MII_M1011_IEVENT 0x13
> > #define MII_M1011_IEVENT_CLEAR 0x0000
> > +#define MII_M1011_IEVENT_WOL_EVENT BIT(7)
> >
> > #define MII_M1011_IMASK 0x12
> > - #define MII_M1011_IMASK_INIT 0x6400
> > + #define MII_M1011_IMASK_INIT 0x6480
> >
> > @@ -195,13 +196,40 @@ struct marvell_priv {
> > bool copper;
> > };
> >
> > +static int marvell_clear_wol_status(struct phy_device *phydev)
> > +{
> > + int err, temp, oldpage;
> > +
> > + oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
> > + if (oldpage < 0)
> > + return oldpage;
> > +
> > + err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
> > + MII_88E1318S_PHY_WOL_PAGE);
> > + if (err < 0)
> > + return err;
> > +
> > + /*
> > + * Clear WOL status so that for next WOL event
> > + * interrupt will be generated by HW
> > + */
> > + temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL);
> > + temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS;
> > + err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp);
>
> is it better to reuse __phy_write()?
phy_modify_paged() would be the best function to use.
Andrew
^ permalink raw reply
* Re: Representing cpu-port of a switch
From: sk.syed2 @ 2018-04-30 13:06 UTC (permalink / raw)
To: Florian Fainelli; +Cc: netdev, jayaram, syeds, andrew, vivien.didelot
In-Reply-To: <F2B0308A-7EE7-4175-A338-18CD27A10EC5@gmail.com>
> Again, pretty standard. What you probably meant is that for host destined or initiated traffic you must use that internal port to egress/ingress frames towards the other external ports.
>
Yes.
>
>>Without tagging, we cant really use DSA, and hide the cpu/dsa port. So
>>if we expose this cpu port as a interface with fixed-phy
>>infrastructure does it create any problems?
>
> Well the fact that you don't have a tagging protocol does not really mean you cannot use DSA. You could create your own tagging format which in your case could be as simple as keeping the prepended DMA packet descriptor and have the parsing of that descriptor be done in a DSA tagger driver.
This would need HW change wont it?
Not that I would necessarily recommend that though, see below.
>
> DSA documentation says one
>>cannot open a socket on cpu/dsa port and send/receive traffic. Is it
>>fairly common to use internal/cpu port as a network interface- i.e,
>>creating a socket and send/receive traffic?
>
> In the context of DSA, all external ports are represented by a network device. This means that the CPU/management port is only used to ingress/egress frames that include the tag which either the switch hardware inserts on its way to the host or conversely that the host must insert to have the switch do the appropriate switching operation. If you do not use tags and you still have a way to target specific external ports the same representation should happen and you do not want to expose the internal port because it will only be used to send/receive traffic from the external ports and it will not be used to send or receive traffic to itself (so to speak).
Just like with DSA you should have the ability to create network
devices that are per-port and you can use the HW provided information
to deliver packets to the appropriate destination port, conversely
send from the appropriate source port.
>
>
The switch HW doesn't have any provision to target specific external
port. I think I didnt make this clear. We would like to integrate a
switch along with an endpoint into a single HW. Meaning we would like
to use internal cpu port as any normal network port to send and
receive traffic. The external network ports will not be used to
send/receive normal traffic(except for control/mgmt frames). So, the
two external front panel ports tied to phys are lets say eth1, eth2.
The cpu port tied to DMAs is represented using fixed-link/always_on
interface say ep0(endpoint). Now applications can open a socket and
send/receive traffic from ep0. The switch does forwarding based on
programmed CAM. Do you see any problem with this approach?
>>One problem is how to report back when network errors(like if both
>>front panel ports are disconnected, the expectation is to bring this
>>cpu port down?).
>
> The CPU port should be considered always UP and the external ports must have proper link notifications in place through PHYLIB/PHYLINK preferably. With link management in place the carrier state is properly managed and the network stack won't send traffic from a port that is not UP.
>
>>We also need to offload all the switch configuration to switch-dev. So
>>the question is using switch-dev without DSA and representing a cpu
>>port as a normal network interface would be ok?
>
> Using switchdev without DSA is absolutely okay, see rocker and mlxsw, but neither of those do represent their CPU/management port for the reasons outlined above that it is only used to convey traffic to/from other ports that have a proper network device representation.
>
May be this is something elementary, but what do you mean by proper
network device representation that cpu port lacks?
^ permalink raw reply
* VRF: ICMPV6 Echo Reply failed to egress if ingress pkt Src is IPV6 Global and Dest is IPV6 Link Local.
From: Sukumar Gopalakrishnan @ 2018-04-30 12:58 UTC (permalink / raw)
To: netdev
VRF: ICMPV6 Echo Reply failed to egress if ingress pkt Src is IPV6
Global and Dest is IPV6 Link Local.
KERNEL VERSION:
================
4.14.28
BUG REPORT:
============
https://bugzilla.kernel.org/show_bug.cgi?id=199573
CONFIGURATION AND PACKET FLOW:
==============================
1) Created VRF device(Vrf_258) and enslaved network device(v1_F4246) to this
VRF. Assigned Global address 2001::1 and fe80::1 to VLAN device.
/exos/bin # ifconfig -a v1_F4246
v1_F4246 Link encap:Ethernet HWaddr 00:04:96:98:C9:18
inet6 addr: 2001::1/64 Scope:Global
inet6 addr: fe80::1/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:52 errors:0 dropped:0 overruns:0 frame:0
TX packets:98 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3024 (2.9 KiB) TX bytes:8116 (7.9 KiB)
/exos/bin # ifconfig -a vrf_258
vrf_258 Link encap:Ethernet HWaddr 00:04:96:98:C9:18
inet addr:127.0.0.1 Mask:255.0.0.0
UP RUNNING NOARP MASTER MTU:65536 Metric:1
RX packets:27 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1512 (1.4 KiB) TX bytes:0 (0.0 B)
/exos/bin # ip link show vrf_258
14: vrf_258: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state
UP mode DEFAULT group default qlen 1000
link/ether 00:04:96:98:c9:18 brd ff:ff:ff:ff:ff:ff
/exos/bin # ip link show v1_F4246
54: v1_F4246: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
master vrf_258 state UNKNOWN mode DEFAULT group default qlen 1000
link/ether 00:04:96:98:c9:18 brd ff:ff:ff:ff:ff:ff
2) Received Ping request to local intf IP 2001::1 from neigbour DUT
with following SRC/Dest.
Rx ICMPV6 Echo Req Pkt's SRC IP = fe800000:0:0:2, DEST IP = 20010000:0:0:1
3) Incoming packet SRC is IPv6 Global address so skb->dev changed to
vrf_258 by ip receive function.
4) Since it is local delivered packet icmpv6_echo_reply() is invoked.
This function tries to send reply with
SRC IP = 20010000:0:0:1
DEST IP = fe800000:0:0:2
flowi6_oif = vrf_dev258
5) ip6_dst_lookup() is failed for this packet and got dropped.
fl6.flowi6_oif = icmp6_iif(skb);
flowi6_oif is having vrf device index when ip6_dst_lookup() is invoked.
Pkt flows to ip6_dst_lookup() ->
ip6_dst_lookup_tail()->ip6_route_output_flags()->l3mdev_link_scope_lookup()->vrf_link_scope_lookup()
There is a check in vrf_link_scope_lookup() which is dropping the reply packet.
In this case flowi6_oif and dev->ifindex are same.
..
if (fl6->flowi6_oif == dev->ifindex) {
dst = &net->ipv6.ip6_null_entry->dst;
dst_hold(dst);
return dst;
}
..
TEMP FIX:
=========
Return Ingress vlan device's ifIndex instead of skb->dev's.
static int icmp6_iif(const struct sk_buff *skb)
{
int iif = IP6CB(skb)->iif; // skb->dev->ifindex;
..
..
}
^ permalink raw reply
* Re: DSA
From: Andrew Lunn @ 2018-04-30 12:50 UTC (permalink / raw)
To: Dave Richards; +Cc: netdev@vger.kernel.org
In-Reply-To: <MWHPR06MB3503CE521D6993C7786A3E93DC8D0@MWHPR06MB3503.namprd06.prod.outlook.com>
On Fri, Apr 27, 2018 at 06:10:55PM +0000, Dave Richards wrote:
> Hello,
>
> I am building a prototype for a new product based on a Lanner, Inc. embedded PC. It is an Intel Celeron-based system with two host I210 GbE chips connected to 2 MV88E6172 chips (one NIC to one switch). Everything appears to show up hardware-wise. My question is, what is the next step? How does DSA know which NICs are intended to be masters? Is this supposed to be auto-detected or is this knowledge supposed to be communicated explicitly. Reading through the DSA driver code I see that there is a check of the OF property list for the device for a "label"/"cpu" property/value pair that needs to be present. Who sets this and when?
Hi Dave
Since you are on Intel, you don't have simple access to Device
tree. So you need to use platform data instead. Or possibly start
hacking on ACPI support for DSA. For the moment, i would suggest
platform data.
I'm also working on a similar setup, intel CPU connected to an
MV88E6532. I have some work in progress code i can share with you,
which i want to submit for inclusion to mainline in the next few
weeks. This adds platform data support to the mv88e6xxx driver, and
will give you an idea how you link the MAC to the switch.
What MDIO bus do you connect the switches to? The i210 MDIO bus? If
so, this is going to cause you a problem. The igb driver ignores the
Linux MDIO and PHY code, and does it all itself. DSA assumes the
switch can be accessed using Linux standard MDIO interfaces. So you
have going to have to hack on the igb driver to make it use standard
MDIO.
Andrew
^ permalink raw reply
* Re: ID of (former "National") TI's PHY DP83848
From: Andrew Lunn @ 2018-04-30 12:22 UTC (permalink / raw)
To: Juergen Borleis; +Cc: netdev, Florian Fainelli
In-Reply-To: <201804271351.05091.jbe@pengutronix.de>
On Fri, Apr 27, 2018 at 01:51:04PM +0200, Juergen Borleis wrote:
> Hi,
>
> I have worked on a DP83848 variant without an interrupt line. While at it, I
> read through all datasheets of existing variants of the DP83848 phy.
>
> Here is what I've found so far:
>
> +--------------+--------------+--------+-----+
> | Variant | Phy ID | Note | IRQ |
> +--------------+--------------+--------+-----+
> | DP83848H | 0x20005c90 | MINI | NO |
> +--------------+--------------+--------+-----+
> | DP83848J | 0x20005c90 | MINI | NO |
> +--------------+--------------+--------+-----+
> | DP83848K | 0x20005c90 | MINI | NO |
> +--------------+--------------+--------+-----+
> | DP83848M | 0x20005c90 | MINI | NO |
> +--------------+--------------+--------+-----+
> | DP83848T | 0x20005c90 | MINI | NO |
> +--------------+--------------+--------+-----+
> | DP83848EP | 0x20005c90 | | YES |
> +--------------+--------------+--------+-----+
> | DP83848HT | 0x20005c90 | | YES |
> +--------------+--------------+--------+-----+
> | DP83848Q | 0x20005ca2 | MINI | NO |
> +--------------+--------------+--------+-----+
> | DP83848V | 0x20005ca2 | | YES |
> +--------------+--------------+--------+-----+
> | DP83848C | 0x20005ca2 | | YES |
> +--------------+--------------+--------+-----+
>
> "MINI" means a less pin count variant.
> "IRQ"-"YES" means, the device has a interrupt line,
> "IRQ"-"NO" means, the device has no interrupt line.
>
> How to deal with interrupts, if the device itself has no interrupt line (and
> uses the same phy ID)? How to deal with the same Phy ID used for different
> devices and different features?
Hi Juergen
Interrupts are always in two parts. One part is the PHY driver side,
saying it supports interrupts, providing the functions to configure
interrupts, check if an interrupt did happen, and acknowledge it. The
second part is somehow specifying which specific interrupt is used,
via device tree, or platform data. Only when both are supplied will
PHYLIB try to use the interrupts.
So it should be safe if they PHY driver always says it supports
interrupts. The platform then must not provide an interrupt number
when there is not one.
As for other features, you probably need to take same approach. How
does a mini differ? Less LEDs? Only RGMII, not GMII?
Andrew
^ permalink raw reply
* Re: [PATCH bpf-next 0/3] bpf: fix formatting for eBPF helper doc
From: Daniel Borkmann @ 2018-04-30 11:57 UTC (permalink / raw)
To: Quentin Monnet, ast; +Cc: netdev, oss-drivers
In-Reply-To: <20180430103905.12863-1-quentin.monnet@netronome.com>
On 04/30/2018 12:39 PM, Quentin Monnet wrote:
> Here is a follow-up set for eBPF helper documentation, with two patches to
> fix formatting issues:
>
> - One to fix an error I introduced with the initial set for the doc.
> - One for the newly added bpf_get_stack(), that is currently not parsed
> correctly with the Python script (function signature is fine, but
> description and return value appear as empty).
>
> There is no change to text contents in this set.
Applied to bpf-next, thanks Quentin!
^ permalink raw reply
* [PATCH net-next V2] cls_flower: Support multiple masks per priority
From: Paul Blakey @ 2018-04-30 11:28 UTC (permalink / raw)
To: Jiri Pirko, Cong Wang, Jamal Hadi Salim, David Miller, netdev
Cc: Yevgeny Kliteynik, Roi Dayan, Shahar Klein, Mark Bloch,
Or Gerlitz, Paul Blakey
Currently flower doesn't support inserting filters with different masks
on a single priority, even if the actual flows (key + mask) inserted
aren't overlapping, as with the use case of offloading openvswitch
datapath flows. Instead one must go up one level, and assign different
priorities for each mask, which will create a different flower
instances.
This patch opens flower to support more than one mask per priority,
and a single flower instance. It does so by adding another hash table
on top of the existing one which will store the different masks,
and the filters that share it.
The user is left with the responsibility of ensuring non overlapping
flows, otherwise precedence is not guaranteed.
Signed-off-by: Paul Blakey <paulb@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
Changes:
V1 -> V2: in fl_init, removed unnessecry err variable, just return direct result instead.
in fl_mask_range, removed extra new line.
commit msg, spelling.
net/sched/cls_flower.c | 275 +++++++++++++++++++++++++++++++------------------
1 file changed, 174 insertions(+), 101 deletions(-)
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index d964e60..eacaaf8 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -61,16 +61,18 @@ struct fl_flow_mask_range {
struct fl_flow_mask {
struct fl_flow_key key;
struct fl_flow_mask_range range;
- struct rcu_head rcu;
+ struct rhash_head ht_node;
+ struct rhashtable ht;
+ struct rhashtable_params filter_ht_params;
+ struct flow_dissector dissector;
+ struct list_head filters;
+ struct rcu_head rcu;
+ struct list_head list;
};
struct cls_fl_head {
struct rhashtable ht;
- struct fl_flow_mask mask;
- struct flow_dissector dissector;
- bool mask_assigned;
- struct list_head filters;
- struct rhashtable_params ht_params;
+ struct list_head masks;
union {
struct work_struct work;
struct rcu_head rcu;
@@ -79,6 +81,7 @@ struct cls_fl_head {
};
struct cls_fl_filter {
+ struct fl_flow_mask *mask;
struct rhash_head ht_node;
struct fl_flow_key mkey;
struct tcf_exts exts;
@@ -94,6 +97,13 @@ struct cls_fl_filter {
struct net_device *hw_dev;
};
+static const struct rhashtable_params mask_ht_params = {
+ .key_offset = offsetof(struct fl_flow_mask, key),
+ .key_len = sizeof(struct fl_flow_key),
+ .head_offset = offsetof(struct fl_flow_mask, ht_node),
+ .automatic_shrinking = true,
+};
+
static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
{
return mask->range.end - mask->range.start;
@@ -103,13 +113,19 @@ static void fl_mask_update_range(struct fl_flow_mask *mask)
{
const u8 *bytes = (const u8 *) &mask->key;
size_t size = sizeof(mask->key);
- size_t i, first = 0, last = size - 1;
+ size_t i, first = 0, last;
- for (i = 0; i < sizeof(mask->key); i++) {
+ for (i = 0; i < size; i++) {
+ if (bytes[i]) {
+ first = i;
+ break;
+ }
+ }
+ last = first;
+ for (i = size - 1; i != first; i--) {
if (bytes[i]) {
- if (!first && i)
- first = i;
last = i;
+ break;
}
}
mask->range.start = rounddown(first, sizeof(long));
@@ -140,12 +156,11 @@ static void fl_clear_masked_range(struct fl_flow_key *key,
memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
}
-static struct cls_fl_filter *fl_lookup(struct cls_fl_head *head,
+static struct cls_fl_filter *fl_lookup(struct fl_flow_mask *mask,
struct fl_flow_key *mkey)
{
- return rhashtable_lookup_fast(&head->ht,
- fl_key_get_start(mkey, &head->mask),
- head->ht_params);
+ return rhashtable_lookup_fast(&mask->ht, fl_key_get_start(mkey, mask),
+ mask->filter_ht_params);
}
static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
@@ -153,28 +168,28 @@ static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
{
struct cls_fl_head *head = rcu_dereference_bh(tp->root);
struct cls_fl_filter *f;
+ struct fl_flow_mask *mask;
struct fl_flow_key skb_key;
struct fl_flow_key skb_mkey;
- if (!atomic_read(&head->ht.nelems))
- return -1;
-
- fl_clear_masked_range(&skb_key, &head->mask);
+ list_for_each_entry_rcu(mask, &head->masks, list) {
+ fl_clear_masked_range(&skb_key, mask);
- skb_key.indev_ifindex = skb->skb_iif;
- /* skb_flow_dissect() does not set n_proto in case an unknown protocol,
- * so do it rather here.
- */
- skb_key.basic.n_proto = skb->protocol;
- skb_flow_dissect_tunnel_info(skb, &head->dissector, &skb_key);
- skb_flow_dissect(skb, &head->dissector, &skb_key, 0);
+ skb_key.indev_ifindex = skb->skb_iif;
+ /* skb_flow_dissect() does not set n_proto in case an unknown
+ * protocol, so do it rather here.
+ */
+ skb_key.basic.n_proto = skb->protocol;
+ skb_flow_dissect_tunnel_info(skb, &mask->dissector, &skb_key);
+ skb_flow_dissect(skb, &mask->dissector, &skb_key, 0);
- fl_set_masked_key(&skb_mkey, &skb_key, &head->mask);
+ fl_set_masked_key(&skb_mkey, &skb_key, mask);
- f = fl_lookup(head, &skb_mkey);
- if (f && !tc_skip_sw(f->flags)) {
- *res = f->res;
- return tcf_exts_exec(skb, &f->exts, res);
+ f = fl_lookup(mask, &skb_mkey);
+ if (f && !tc_skip_sw(f->flags)) {
+ *res = f->res;
+ return tcf_exts_exec(skb, &f->exts, res);
+ }
}
return -1;
}
@@ -187,11 +202,28 @@ static int fl_init(struct tcf_proto *tp)
if (!head)
return -ENOBUFS;
- INIT_LIST_HEAD_RCU(&head->filters);
+ INIT_LIST_HEAD_RCU(&head->masks);
rcu_assign_pointer(tp->root, head);
idr_init(&head->handle_idr);
- return 0;
+ return rhashtable_init(&head->ht, &mask_ht_params);
+}
+
+static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask,
+ bool async)
+{
+ if (!list_empty(&mask->filters))
+ return false;
+
+ rhashtable_remove_fast(&head->ht, &mask->ht_node, mask_ht_params);
+ rhashtable_destroy(&mask->ht);
+ list_del_rcu(&mask->list);
+ if (async)
+ kfree_rcu(mask, rcu);
+ else
+ kfree(mask);
+
+ return true;
}
static void __fl_destroy_filter(struct cls_fl_filter *f)
@@ -234,8 +266,6 @@ static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f,
}
static int fl_hw_replace_filter(struct tcf_proto *tp,
- struct flow_dissector *dissector,
- struct fl_flow_key *mask,
struct cls_fl_filter *f,
struct netlink_ext_ack *extack)
{
@@ -247,8 +277,8 @@ static int fl_hw_replace_filter(struct tcf_proto *tp,
tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
cls_flower.command = TC_CLSFLOWER_REPLACE;
cls_flower.cookie = (unsigned long) f;
- cls_flower.dissector = dissector;
- cls_flower.mask = mask;
+ cls_flower.dissector = &f->mask->dissector;
+ cls_flower.mask = &f->mask->key;
cls_flower.key = &f->mkey;
cls_flower.exts = &f->exts;
cls_flower.classid = f->res.classid;
@@ -283,28 +313,31 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
&cls_flower, false);
}
-static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
+static bool __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
struct netlink_ext_ack *extack)
{
struct cls_fl_head *head = rtnl_dereference(tp->root);
+ bool async = tcf_exts_get_net(&f->exts);
+ bool last;
idr_remove(&head->handle_idr, f->handle);
list_del_rcu(&f->list);
+ last = fl_mask_put(head, f->mask, async);
if (!tc_skip_hw(f->flags))
fl_hw_destroy_filter(tp, f, extack);
tcf_unbind_filter(tp, &f->res);
- if (tcf_exts_get_net(&f->exts))
+ if (async)
call_rcu(&f->rcu, fl_destroy_filter);
else
__fl_destroy_filter(f);
+
+ return last;
}
static void fl_destroy_sleepable(struct work_struct *work)
{
struct cls_fl_head *head = container_of(work, struct cls_fl_head,
work);
- if (head->mask_assigned)
- rhashtable_destroy(&head->ht);
kfree(head);
module_put(THIS_MODULE);
}
@@ -320,10 +353,15 @@ static void fl_destroy_rcu(struct rcu_head *rcu)
static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
{
struct cls_fl_head *head = rtnl_dereference(tp->root);
+ struct fl_flow_mask *mask, *next_mask;
struct cls_fl_filter *f, *next;
- list_for_each_entry_safe(f, next, &head->filters, list)
- __fl_delete(tp, f, extack);
+ list_for_each_entry_safe(mask, next_mask, &head->masks, list) {
+ list_for_each_entry_safe(f, next, &mask->filters, list) {
+ if (__fl_delete(tp, f, extack))
+ break;
+ }
+ }
idr_destroy(&head->handle_idr);
__module_get(THIS_MODULE);
@@ -715,14 +753,14 @@ static int fl_set_key(struct net *net, struct nlattr **tb,
return ret;
}
-static bool fl_mask_eq(struct fl_flow_mask *mask1,
- struct fl_flow_mask *mask2)
+static void fl_mask_copy(struct fl_flow_mask *dst,
+ struct fl_flow_mask *src)
{
- const long *lmask1 = fl_key_get_start(&mask1->key, mask1);
- const long *lmask2 = fl_key_get_start(&mask2->key, mask2);
+ const void *psrc = fl_key_get_start(&src->key, src);
+ void *pdst = fl_key_get_start(&dst->key, src);
- return !memcmp(&mask1->range, &mask2->range, sizeof(mask1->range)) &&
- !memcmp(lmask1, lmask2, fl_mask_range(mask1));
+ memcpy(pdst, psrc, fl_mask_range(src));
+ dst->range = src->range;
}
static const struct rhashtable_params fl_ht_params = {
@@ -731,14 +769,13 @@ static const struct rhashtable_params fl_ht_params = {
.automatic_shrinking = true,
};
-static int fl_init_hashtable(struct cls_fl_head *head,
- struct fl_flow_mask *mask)
+static int fl_init_mask_hashtable(struct fl_flow_mask *mask)
{
- head->ht_params = fl_ht_params;
- head->ht_params.key_len = fl_mask_range(mask);
- head->ht_params.key_offset += mask->range.start;
+ mask->filter_ht_params = fl_ht_params;
+ mask->filter_ht_params.key_len = fl_mask_range(mask);
+ mask->filter_ht_params.key_offset += mask->range.start;
- return rhashtable_init(&head->ht, &head->ht_params);
+ return rhashtable_init(&mask->ht, &mask->filter_ht_params);
}
#define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member)
@@ -761,8 +798,7 @@ static int fl_init_hashtable(struct cls_fl_head *head,
FL_KEY_SET(keys, cnt, id, member); \
} while(0);
-static void fl_init_dissector(struct cls_fl_head *head,
- struct fl_flow_mask *mask)
+static void fl_init_dissector(struct fl_flow_mask *mask)
{
struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
size_t cnt = 0;
@@ -802,31 +838,66 @@ static void fl_init_dissector(struct cls_fl_head *head,
FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp);
- skb_flow_dissector_init(&head->dissector, keys, cnt);
+ skb_flow_dissector_init(&mask->dissector, keys, cnt);
+}
+
+static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head,
+ struct fl_flow_mask *mask)
+{
+ struct fl_flow_mask *newmask;
+ int err;
+
+ newmask = kzalloc(sizeof(*newmask), GFP_KERNEL);
+ if (!newmask)
+ return ERR_PTR(-ENOMEM);
+
+ fl_mask_copy(newmask, mask);
+
+ err = fl_init_mask_hashtable(newmask);
+ if (err)
+ goto errout_free;
+
+ fl_init_dissector(newmask);
+
+ INIT_LIST_HEAD_RCU(&newmask->filters);
+
+ err = rhashtable_insert_fast(&head->ht, &newmask->ht_node,
+ mask_ht_params);
+ if (err)
+ goto errout_destroy;
+
+ list_add_tail_rcu(&newmask->list, &head->masks);
+
+ return newmask;
+
+errout_destroy:
+ rhashtable_destroy(&newmask->ht);
+errout_free:
+ kfree(newmask);
+
+ return ERR_PTR(err);
}
static int fl_check_assign_mask(struct cls_fl_head *head,
+ struct cls_fl_filter *fnew,
+ struct cls_fl_filter *fold,
struct fl_flow_mask *mask)
{
- int err;
+ struct fl_flow_mask *newmask;
- if (head->mask_assigned) {
- if (!fl_mask_eq(&head->mask, mask))
+ fnew->mask = rhashtable_lookup_fast(&head->ht, mask, mask_ht_params);
+ if (!fnew->mask) {
+ if (fold)
return -EINVAL;
- else
- return 0;
- }
- /* Mask is not assigned yet. So assign it and init hashtable
- * according to that.
- */
- err = fl_init_hashtable(head, mask);
- if (err)
- return err;
- memcpy(&head->mask, mask, sizeof(head->mask));
- head->mask_assigned = true;
+ newmask = fl_create_new_mask(head, mask);
+ if (IS_ERR(newmask))
+ return PTR_ERR(newmask);
- fl_init_dissector(head, mask);
+ fnew->mask = newmask;
+ } else if (fold && fold->mask == fnew->mask) {
+ return -EINVAL;
+ }
return 0;
}
@@ -924,30 +995,26 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
if (err)
goto errout_idr;
- err = fl_check_assign_mask(head, &mask);
+ err = fl_check_assign_mask(head, fnew, fold, &mask);
if (err)
goto errout_idr;
if (!tc_skip_sw(fnew->flags)) {
- if (!fold && fl_lookup(head, &fnew->mkey)) {
+ if (!fold && fl_lookup(fnew->mask, &fnew->mkey)) {
err = -EEXIST;
- goto errout_idr;
+ goto errout_mask;
}
- err = rhashtable_insert_fast(&head->ht, &fnew->ht_node,
- head->ht_params);
+ err = rhashtable_insert_fast(&fnew->mask->ht, &fnew->ht_node,
+ fnew->mask->filter_ht_params);
if (err)
- goto errout_idr;
+ goto errout_mask;
}
if (!tc_skip_hw(fnew->flags)) {
- err = fl_hw_replace_filter(tp,
- &head->dissector,
- &mask.key,
- fnew,
- extack);
+ err = fl_hw_replace_filter(tp, fnew, extack);
if (err)
- goto errout_idr;
+ goto errout_mask;
}
if (!tc_in_hw(fnew->flags))
@@ -955,8 +1022,9 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
if (fold) {
if (!tc_skip_sw(fold->flags))
- rhashtable_remove_fast(&head->ht, &fold->ht_node,
- head->ht_params);
+ rhashtable_remove_fast(&fold->mask->ht,
+ &fold->ht_node,
+ fold->mask->filter_ht_params);
if (!tc_skip_hw(fold->flags))
fl_hw_destroy_filter(tp, fold, NULL);
}
@@ -970,12 +1038,15 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
tcf_exts_get_net(&fold->exts);
call_rcu(&fold->rcu, fl_destroy_filter);
} else {
- list_add_tail_rcu(&fnew->list, &head->filters);
+ list_add_tail_rcu(&fnew->list, &fnew->mask->filters);
}
kfree(tb);
return 0;
+errout_mask:
+ fl_mask_put(head, fnew->mask, false);
+
errout_idr:
if (fnew->handle)
idr_remove(&head->handle_idr, fnew->handle);
@@ -994,10 +1065,10 @@ static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
struct cls_fl_filter *f = arg;
if (!tc_skip_sw(f->flags))
- rhashtable_remove_fast(&head->ht, &f->ht_node,
- head->ht_params);
+ rhashtable_remove_fast(&f->mask->ht, &f->ht_node,
+ f->mask->filter_ht_params);
__fl_delete(tp, f, extack);
- *last = list_empty(&head->filters);
+ *last = list_empty(&head->masks);
return 0;
}
@@ -1005,16 +1076,19 @@ static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg)
{
struct cls_fl_head *head = rtnl_dereference(tp->root);
struct cls_fl_filter *f;
-
- list_for_each_entry_rcu(f, &head->filters, list) {
- if (arg->count < arg->skip)
- goto skip;
- if (arg->fn(tp, f, arg) < 0) {
- arg->stop = 1;
- break;
- }
+ struct fl_flow_mask *mask;
+
+ list_for_each_entry_rcu(mask, &head->masks, list) {
+ list_for_each_entry_rcu(f, &mask->filters, list) {
+ if (arg->count < arg->skip)
+ goto skip;
+ if (arg->fn(tp, f, arg) < 0) {
+ arg->stop = 1;
+ break;
+ }
skip:
- arg->count++;
+ arg->count++;
+ }
}
}
@@ -1150,7 +1224,6 @@ static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask)
static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh,
struct sk_buff *skb, struct tcmsg *t)
{
- struct cls_fl_head *head = rtnl_dereference(tp->root);
struct cls_fl_filter *f = fh;
struct nlattr *nest;
struct fl_flow_key *key, *mask;
@@ -1169,7 +1242,7 @@ static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh,
goto nla_put_failure;
key = &f->key;
- mask = &head->mask.key;
+ mask = &f->mask->key;
if (mask->indev_ifindex) {
struct net_device *dev;
--
2.7.4
^ permalink raw reply related
* [PATCH bpf-next 3/3] bpf: update bpf.h uapi header for tools
From: Quentin Monnet @ 2018-04-30 10:39 UTC (permalink / raw)
To: daniel, ast; +Cc: netdev, oss-drivers, quentin.monnet
In-Reply-To: <20180430103905.12863-1-quentin.monnet@netronome.com>
Bring fixes for eBPF helper documentation formatting to bpf.h under
tools/ as well.
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tools/include/uapi/linux/bpf.h | 62 +++++++++++++++++++++---------------------
1 file changed, 31 insertions(+), 31 deletions(-)
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 23b334bba1a6..8daef7326bb7 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -828,12 +828,12 @@ union bpf_attr {
*
* Also, be aware that the newer helper
* **bpf_perf_event_read_value**\ () is recommended over
- * **bpf_perf_event_read*\ () in general. The latter has some ABI
+ * **bpf_perf_event_read**\ () in general. The latter has some ABI
* quirks where error and counter value are used as a return code
* (which is wrong to do since ranges may overlap). This issue is
- * fixed with bpf_perf_event_read_value(), which at the same time
- * provides more features over the **bpf_perf_event_read**\ ()
- * interface. Please refer to the description of
+ * fixed with **bpf_perf_event_read_value**\ (), which at the same
+ * time provides more features over the **bpf_perf_event_read**\
+ * () interface. Please refer to the description of
* **bpf_perf_event_read_value**\ () for details.
* Return
* The value of the perf event counter read from the map, or a
@@ -1770,33 +1770,33 @@ union bpf_attr {
*
* int bpf_get_stack(struct pt_regs *regs, void *buf, u32 size, u64 flags)
* Description
- * Return a user or a kernel stack in bpf program provided buffer.
- * To achieve this, the helper needs *ctx*, which is a pointer
- * to the context on which the tracing program is executed.
- * To store the stacktrace, the bpf program provides *buf* with
- * a nonnegative *size*.
- *
- * The last argument, *flags*, holds the number of stack frames to
- * skip (from 0 to 255), masked with
- * **BPF_F_SKIP_FIELD_MASK**. The next bits can be used to set
- * the following flags:
- *
- * **BPF_F_USER_STACK**
- * Collect a user space stack instead of a kernel stack.
- * **BPF_F_USER_BUILD_ID**
- * Collect buildid+offset instead of ips for user stack,
- * only valid if **BPF_F_USER_STACK** is also specified.
- *
- * **bpf_get_stack**\ () can collect up to
- * **PERF_MAX_STACK_DEPTH** both kernel and user frames, subject
- * to sufficient large buffer size. Note that
- * this limit can be controlled with the **sysctl** program, and
- * that it should be manually increased in order to profile long
- * user stacks (such as stacks for Java programs). To do so, use:
- *
- * ::
- *
- * # sysctl kernel.perf_event_max_stack=<new value>
+ * Return a user or a kernel stack in bpf program provided buffer.
+ * To achieve this, the helper needs *ctx*, which is a pointer
+ * to the context on which the tracing program is executed.
+ * To store the stacktrace, the bpf program provides *buf* with
+ * a nonnegative *size*.
+ *
+ * The last argument, *flags*, holds the number of stack frames to
+ * skip (from 0 to 255), masked with
+ * **BPF_F_SKIP_FIELD_MASK**. The next bits can be used to set
+ * the following flags:
+ *
+ * **BPF_F_USER_STACK**
+ * Collect a user space stack instead of a kernel stack.
+ * **BPF_F_USER_BUILD_ID**
+ * Collect buildid+offset instead of ips for user stack,
+ * only valid if **BPF_F_USER_STACK** is also specified.
+ *
+ * **bpf_get_stack**\ () can collect up to
+ * **PERF_MAX_STACK_DEPTH** both kernel and user frames, subject
+ * to sufficient large buffer size. Note that
+ * this limit can be controlled with the **sysctl** program, and
+ * that it should be manually increased in order to profile long
+ * user stacks (such as stacks for Java programs). To do so, use:
+ *
+ * ::
+ *
+ * # sysctl kernel.perf_event_max_stack=<new value>
*
* Return
* a non-negative value equal to or less than size on success, or
--
2.14.1
^ permalink raw reply related
* [PATCH bpf-next 2/3] bpf: fix formatting for bpf_get_stack() helper doc
From: Quentin Monnet @ 2018-04-30 10:39 UTC (permalink / raw)
To: daniel, ast; +Cc: netdev, oss-drivers, quentin.monnet, Yonghong Song
In-Reply-To: <20180430103905.12863-1-quentin.monnet@netronome.com>
Fix formatting (indent) for bpf_get_stack() helper documentation, so
that the doc is rendered correctly with the Python script.
Fixes: c195651e565a ("bpf: add bpf_get_stack helper")
Cc: Yonghong Song <yhs@fb.com>
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
---
Note: The error was a missing space between the '*' marking the
comments, and the tabs. This expected mixed indent comes from the fact I
started to write the doc as a RST, then copied my contents (tabs
included) in the header file and added a " * " (with a space) prefix
everywhere.
On a second thought, using such indent style was maybe... not my best idea
ever. Anyway, if indent for documenting eBPF helpers really gets to painful, we
could relax parsing rules in the Python script to make things easier.
---
include/uapi/linux/bpf.h | 54 ++++++++++++++++++++++++------------------------
1 file changed, 27 insertions(+), 27 deletions(-)
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 530ff6588d8f..8daef7326bb7 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1770,33 +1770,33 @@ union bpf_attr {
*
* int bpf_get_stack(struct pt_regs *regs, void *buf, u32 size, u64 flags)
* Description
- * Return a user or a kernel stack in bpf program provided buffer.
- * To achieve this, the helper needs *ctx*, which is a pointer
- * to the context on which the tracing program is executed.
- * To store the stacktrace, the bpf program provides *buf* with
- * a nonnegative *size*.
- *
- * The last argument, *flags*, holds the number of stack frames to
- * skip (from 0 to 255), masked with
- * **BPF_F_SKIP_FIELD_MASK**. The next bits can be used to set
- * the following flags:
- *
- * **BPF_F_USER_STACK**
- * Collect a user space stack instead of a kernel stack.
- * **BPF_F_USER_BUILD_ID**
- * Collect buildid+offset instead of ips for user stack,
- * only valid if **BPF_F_USER_STACK** is also specified.
- *
- * **bpf_get_stack**\ () can collect up to
- * **PERF_MAX_STACK_DEPTH** both kernel and user frames, subject
- * to sufficient large buffer size. Note that
- * this limit can be controlled with the **sysctl** program, and
- * that it should be manually increased in order to profile long
- * user stacks (such as stacks for Java programs). To do so, use:
- *
- * ::
- *
- * # sysctl kernel.perf_event_max_stack=<new value>
+ * Return a user or a kernel stack in bpf program provided buffer.
+ * To achieve this, the helper needs *ctx*, which is a pointer
+ * to the context on which the tracing program is executed.
+ * To store the stacktrace, the bpf program provides *buf* with
+ * a nonnegative *size*.
+ *
+ * The last argument, *flags*, holds the number of stack frames to
+ * skip (from 0 to 255), masked with
+ * **BPF_F_SKIP_FIELD_MASK**. The next bits can be used to set
+ * the following flags:
+ *
+ * **BPF_F_USER_STACK**
+ * Collect a user space stack instead of a kernel stack.
+ * **BPF_F_USER_BUILD_ID**
+ * Collect buildid+offset instead of ips for user stack,
+ * only valid if **BPF_F_USER_STACK** is also specified.
+ *
+ * **bpf_get_stack**\ () can collect up to
+ * **PERF_MAX_STACK_DEPTH** both kernel and user frames, subject
+ * to sufficient large buffer size. Note that
+ * this limit can be controlled with the **sysctl** program, and
+ * that it should be manually increased in order to profile long
+ * user stacks (such as stacks for Java programs). To do so, use:
+ *
+ * ::
+ *
+ * # sysctl kernel.perf_event_max_stack=<new value>
*
* Return
* a non-negative value equal to or less than size on success, or
--
2.14.1
^ permalink raw reply related
* [PATCH bpf-next 1/3] bpf: fix formatting for bpf_perf_event_read() helper doc
From: Quentin Monnet @ 2018-04-30 10:39 UTC (permalink / raw)
To: daniel, ast; +Cc: netdev, oss-drivers, quentin.monnet
In-Reply-To: <20180430103905.12863-1-quentin.monnet@netronome.com>
Some edits brought to the last iteration of BPF helper functions
documentation introduced an error with RST formatting. As a result, most
of one paragraph is rendered in bold text when only the name of a helper
should be. Fix it, and fix formatting of another function name in the
same paragraph.
Fixes: c6b5fb8690fa ("bpf: add documentation for eBPF helpers (42-50)")
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
---
include/uapi/linux/bpf.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 23b334bba1a6..530ff6588d8f 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -828,12 +828,12 @@ union bpf_attr {
*
* Also, be aware that the newer helper
* **bpf_perf_event_read_value**\ () is recommended over
- * **bpf_perf_event_read*\ () in general. The latter has some ABI
+ * **bpf_perf_event_read**\ () in general. The latter has some ABI
* quirks where error and counter value are used as a return code
* (which is wrong to do since ranges may overlap). This issue is
- * fixed with bpf_perf_event_read_value(), which at the same time
- * provides more features over the **bpf_perf_event_read**\ ()
- * interface. Please refer to the description of
+ * fixed with **bpf_perf_event_read_value**\ (), which at the same
+ * time provides more features over the **bpf_perf_event_read**\
+ * () interface. Please refer to the description of
* **bpf_perf_event_read_value**\ () for details.
* Return
* The value of the perf event counter read from the map, or a
--
2.14.1
^ permalink raw reply related
* [PATCH bpf-next 0/3] bpf: fix formatting for eBPF helper doc
From: Quentin Monnet @ 2018-04-30 10:39 UTC (permalink / raw)
To: daniel, ast; +Cc: netdev, oss-drivers, quentin.monnet
Hi,
Here is a follow-up set for eBPF helper documentation, with two patches to
fix formatting issues:
- One to fix an error I introduced with the initial set for the doc.
- One for the newly added bpf_get_stack(), that is currently not parsed
correctly with the Python script (function signature is fine, but
description and return value appear as empty).
There is no change to text contents in this set.
Quentin Monnet (3):
bpf: fix formatting for bpf_perf_event_read() helper doc
bpf: fix formatting for bpf_get_stack() helper documentation
bpf: update bpf.h uapi header for tools
include/uapi/linux/bpf.h | 62 +++++++++++++++++++++---------------------
tools/include/uapi/linux/bpf.h | 62 +++++++++++++++++++++---------------------
2 files changed, 62 insertions(+), 62 deletions(-)
--
2.14.1
^ permalink raw reply
* Re: ipw2100: fix spelling mistake: "decsribed" -> "described"
From: Kalle Valo @ 2018-04-30 10:38 UTC (permalink / raw)
To: Colin Ian King
Cc: Stanislav Yakovlev, linux-wireless, netdev, kernel-janitors,
linux-kernel
In-Reply-To: <20180428223108.20458-1-colin.king@canonical.com>
Colin Ian King <colin.king@canonical.com> wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> Trivial fix to spelling mistake in comment and in the ord_data text
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
Patch applied to wireless-drivers-next.git, thanks.
3ea0a58cf9cf ipw2100: fix spelling mistake: "decsribed" -> "described"
--
https://patchwork.kernel.org/patch/10370407/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: rt2x00: fix spelling mistake in various macros, UKNOWN -> UNKNOWN
From: Kalle Valo @ 2018-04-30 10:35 UTC (permalink / raw)
To: Colin Ian King
Cc: Stanislaw Gruszka, Helmut Schaa, linux-wireless, netdev,
kernel-janitors, linux-kernel
In-Reply-To: <20180418114750.1978-1-colin.king@canonical.com>
Colin Ian King <colin.king@canonical.com> wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> Rename several macros that contain mispellings of UNKNOWN
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> Acked-by: Stanislaw Gruszka <sgruszka@redhat.com>
Patch applied to wireless-drivers-next.git, thanks.
cc282a0c5f08 rt2x00: fix spelling mistake in various macros, UKNOWN -> UNKNOWN
--
https://patchwork.kernel.org/patch/10348023/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: rsi_91x: fix uninitialized variable
From: Kalle Valo @ 2018-04-30 10:34 UTC (permalink / raw)
To: Gustavo A. R. Silva
Cc: Amitkumar Karwar, linux-wireless, netdev, linux-kernel,
Gustavo A. R. Silva
In-Reply-To: <20180426131324.GA982@embeddedor.com>
"Gustavo A. R. Silva" <gustavo@embeddedor.com> wrote:
> There is a potential execution path in which variable ret is returned
> without being properly initialized previously.
>
> Fix this by storing the value returned by function
> rsi_usb_master_reg_write into _ret_.
>
> Addresses-Coverity-ID: 1468407 ("Uninitialized scalar variable")
> Fixes: 16d3bb7b2f37 ("rsi: disable fw watchdog timer during reset")
> Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
Patch applied to wireless-drivers-next.git, thanks.
48c6b5c9c118 rsi_91x: fix uninitialized variable
--
https://patchwork.kernel.org/patch/10365985/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: rsi_91x: fix structurally dead code
From: Kalle Valo @ 2018-04-30 10:33 UTC (permalink / raw)
To: Gustavo A. R. Silva
Cc: Prameela Rani Garnepudi, linux-wireless, netdev, linux-kernel,
Gustavo A. R. Silva
In-Reply-To: <20180426130138.GA440@embeddedor.com>
"Gustavo A. R. Silva" <gustavo@embeddedor.com> wrote:
> Function rsi_hal_key_config returns before reaching code at line
> 922 if (status), hence this code is structurally dead.
>
> Fix this by storing the value returned by rsi_hal_load_key
> into _status_ for its further evaluation and use.
>
> Addresses-Coverity-ID: 1468409 ("Structurally dead code")
> Fixes: 4fd6c4762f37 ("rsi: roaming enhancements")
> Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
Patch applied to wireless-drivers-next.git, thanks.
e1fd7ceec194 rsi_91x: fix structurally dead code
--
https://patchwork.kernel.org/patch/10365997/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: qtnfmac: fix qtnf_netdev_hard_start_xmit()'s return type
From: Kalle Valo @ 2018-04-30 10:28 UTC (permalink / raw)
To: Luc Van Oostenryck
Cc: linux-kernel, Luc Van Oostenryck, Igor Mitsyanko, Avinash Patil,
Sergey Matyukevich, Vasily Ulyanov, Kees Cook, linux-wireless,
netdev
In-Reply-To: <20180424131810.4963-1-luc.vanoostenryck@gmail.com>
Luc Van Oostenryck <luc.vanoostenryck@gmail.com> wrote:
> The method ndo_start_xmit() is defined as returning an 'netdev_tx_t',
> which is a typedef for an enum type, but the implementation in this
> driver returns an 'int'.
>
> Fix this by returning 'netdev_tx_t' in this driver too.
>
> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
> Reviewed-by: Sergey Matyukevich <sergey.matyukevich.os@quantenna.com>
Patch applied to wireless-drivers-next.git, thanks.
3ff6ee28535f qtnfmac: fix qtnf_netdev_hard_start_xmit()'s return type
--
https://patchwork.kernel.org/patch/10359851/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: net: wireless: b43legacy: Replace GFP_ATOMIC with GFP_KERNEL in dma_tx_fragment
From: Kalle Valo @ 2018-04-30 10:27 UTC (permalink / raw)
To: Jia-Ju Bai
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Jia-Ju Bai,
b43-dev-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Larry.Finger-tQ5ms3gMjBLk1uMJSBkQmQ
In-Reply-To: <1523368459-32128-1-git-send-email-baijiaju1990-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Jia-Ju Bai <baijiaju1990-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> dma_tx_fragment() is never called in atomic context.
>
> dma_tx_fragment() is only called by b43legacy_dma_tx(), which is
> only called by b43legacy_tx_work().
> b43legacy_tx_work() is only set a parameter of INIT_WORK() in
> b43legacy_wireless_init().
>
> Despite never getting called from atomic context,
> dma_tx_fragment() calls alloc_skb() with GFP_ATOMIC,
> which does not sleep for allocation.
> GFP_ATOMIC is not necessary and can be replaced with GFP_KERNEL,
> which can sleep and improve the possibility of sucessful allocation.
>
> This is found by a static analysis tool named DCNS written by myself.
> And I also manually check it.
>
> Signed-off-by: Jia-Ju Bai <baijiaju1990-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Patch applied to wireless-drivers-next.git, thanks.
6e1d8d1470b2 net: wireless: b43legacy: Replace GFP_ATOMIC with GFP_KERNEL in dma_tx_fragment
--
https://patchwork.kernel.org/patch/10333217/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: net: wireless: b43legacy: Replace GFP_ATOMIC with GFP_KERNEL in dma_tx_fragment
From: Kalle Valo @ 2018-04-30 10:27 UTC (permalink / raw)
To: Jia-Ju Bai
Cc: Larry.Finger, linux-wireless, b43-dev, netdev, linux-kernel,
Jia-Ju Bai
In-Reply-To: <1523368459-32128-1-git-send-email-baijiaju1990@gmail.com>
Jia-Ju Bai <baijiaju1990@gmail.com> wrote:
> dma_tx_fragment() is never called in atomic context.
>
> dma_tx_fragment() is only called by b43legacy_dma_tx(), which is
> only called by b43legacy_tx_work().
> b43legacy_tx_work() is only set a parameter of INIT_WORK() in
> b43legacy_wireless_init().
>
> Despite never getting called from atomic context,
> dma_tx_fragment() calls alloc_skb() with GFP_ATOMIC,
> which does not sleep for allocation.
> GFP_ATOMIC is not necessary and can be replaced with GFP_KERNEL,
> which can sleep and improve the possibility of sucessful allocation.
>
> This is found by a static analysis tool named DCNS written by myself.
> And I also manually check it.
>
> Signed-off-by: Jia-Ju Bai <baijiaju1990@gmail.com>
Patch applied to wireless-drivers-next.git, thanks.
6e1d8d1470b2 net: wireless: b43legacy: Replace GFP_ATOMIC with GFP_KERNEL in dma_tx_fragment
--
https://patchwork.kernel.org/patch/10333217/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: mwifiex: fix spelling mistake: "capabilties" -> "capabilities"
From: Kalle Valo @ 2018-04-30 10:25 UTC (permalink / raw)
To: Colin Ian King
Cc: Amitkumar Karwar, Nishant Sarmukadam, Ganapathi Bhat, Xinming Hu,
linux-wireless, netdev, kernel-janitors, linux-kernel
In-Reply-To: <20180428093621.6806-1-colin.king@canonical.com>
Colin Ian King <colin.king@canonical.com> wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> Trivial fix to spelling mistake in function names and text strings
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
Failed to apply:
error: patch failed: drivers/net/wireless/marvell/mwifiex/sta_event.c:933
error: drivers/net/wireless/marvell/mwifiex/sta_event.c: patch does not apply
error: Did you hand edit your patch?
It does not apply to blobs recorded in its index.
Applying: mwifiex: fix spelling mistake: "capabilties" -> "capabilities"
Using index info to reconstruct a base tree...
Patch failed at 0001 mwifiex: fix spelling mistake: "capabilties" -> "capabilities"
The copy of the patch that failed is found in: .git/rebase-apply/patch
Patch set to Changes Requested.
--
https://patchwork.kernel.org/patch/10370183/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: mwifiex: fix mwifiex_hard_start_xmit()'s return type
From: Kalle Valo @ 2018-04-30 10:23 UTC (permalink / raw)
To: Luc Van Oostenryck
Cc: linux-kernel, Luc Van Oostenryck, Amitkumar Karwar,
Nishant Sarmukadam, Ganapathi Bhat, Xinming Hu, linux-wireless,
netdev
In-Reply-To: <20180424131802.4913-1-luc.vanoostenryck@gmail.com>
Luc Van Oostenryck <luc.vanoostenryck@gmail.com> wrote:
> The method ndo_start_xmit() is defined as returning an 'netdev_tx_t',
> which is a typedef for an enum type, but the implementation in this
> driver returns an 'int'.
>
> Fix this by returning 'netdev_tx_t' in this driver too.
>
> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
Patch applied to wireless-drivers-next.git, thanks.
c126e1995f79 mwifiex: fix mwifiex_hard_start_xmit()'s return type
--
https://patchwork.kernel.org/patch/10359857/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: [PATCH v2 2/2] selftests/bpf: update .gitignore files
From: Daniel Borkmann @ 2018-04-30 10:14 UTC (permalink / raw)
To: Sirio Balmelli; +Cc: netdev
In-Reply-To: <20180430071743.65rdmn3ltdckpn3i@vm4>
On 04/30/2018 09:17 AM, Sirio Balmelli wrote:
> Build products polluting Git cache. Add to respective .gitignore files.
>
> Signed-off-by: Sirio Balmelli <sirio@b-ad.ch>
> ---
> tools/bpf/bpftool/.gitignore | 12 ++++++++++++
> tools/testing/selftests/bpf/.gitignore | 1 +
> 2 files changed, 13 insertions(+)
> create mode 100644 tools/bpf/bpftool/.gitignore
>
> diff --git a/tools/bpf/bpftool/.gitignore b/tools/bpf/bpftool/.gitignore
> new file mode 100644
> index 0000000..427243f
> --- /dev/null
> +++ b/tools/bpf/bpftool/.gitignore
> @@ -0,0 +1,12 @@
> +bpftool
> +cfg.d
> +cgroup.d
> +common.d
> +disasm.d
> +FEATURE-DUMP.bpftool
> +jit_disasm.d
> +json_writer.d
> +main.d
> +map.d
> +prog.d
> +xlated_dumper.d
Lets do instead: *.d
> diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore
> index 3e3b3ce..adc8e54 100644
> --- a/tools/testing/selftests/bpf/.gitignore
> +++ b/tools/testing/selftests/bpf/.gitignore
> @@ -16,3 +16,4 @@ test_sock
> test_sock_addr
> urandom_read
> test_btf
> +test_sockmap
>
^ permalink raw reply
* [PATCH net-next v6 3/3] cxgb4: collect hardware dump in second kernel
From: Rahul Lakkireddy @ 2018-04-30 10:14 UTC (permalink / raw)
To: netdev, kexec, linux-fsdevel, linux-kernel
Cc: davem, viro, ebiederm, stephen, akpm, torvalds, ganeshgr,
nirranjan, indranil, Rahul Lakkireddy
In-Reply-To: <cover.1525082669.git.rahul.lakkireddy@chelsio.com>
Register callback to collect hardware/firmware dumps in second kernel
before hardware/firmware is initialized. The dumps for each device
will be available as elf notes in /proc/vmcore in second kernel.
Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
---
v6:
- Added "CHELSIO" string as vendor identifier in the Elf Note name.
v5:
- No changes.
v4:
- No changes.
v3:
- Replaced all crashdd* with vmcoredd*.
- Replaced crashdd_add_dump() with vmcore_add_device_dump().
- Updated comments and commit message.
v2:
- No Changes.
Changes since rfc v2:
- Update comments and commit message for sysfs change.
rfc v2:
- Updated dump registration to the new API in patch 1.
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 4 ++++
drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 27 ++++++++++++++++++++++++
drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h | 4 ++++
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 10 +++++++++
4 files changed, 45 insertions(+)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 688f95440af2..01e7aad4ce5b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -50,6 +50,7 @@
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/ptp_classify.h>
+#include <linux/crash_dump.h>
#include <asm/io.h>
#include "t4_chip_type.h"
#include "cxgb4_uld.h"
@@ -964,6 +965,9 @@ struct adapter {
struct hma_data hma;
struct srq_data *srq;
+
+ /* Dump buffer for collecting logs in kdump kernel */
+ struct vmcoredd_data vmcoredd;
};
/* Support for "sched-class" command to allow a TX Scheduling Class to be
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
index 143686c60234..16eb47f37825 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
@@ -488,3 +488,30 @@ void cxgb4_init_ethtool_dump(struct adapter *adapter)
adapter->eth_dump.version = adapter->params.fw_vers;
adapter->eth_dump.len = 0;
}
+
+static int cxgb4_cudbg_vmcoredd_collect(struct vmcoredd_data *data, void *buf)
+{
+ struct adapter *adap = container_of(data, struct adapter, vmcoredd);
+ u32 len = data->size;
+
+ return cxgb4_cudbg_collect(adap, buf, &len, CXGB4_ETH_DUMP_ALL);
+}
+
+int cxgb4_cudbg_vmcore_add_dump(struct adapter *adap)
+{
+ struct vmcoredd_data *data = &adap->vmcoredd;
+ u32 len;
+
+ len = sizeof(struct cudbg_hdr) +
+ sizeof(struct cudbg_entity_hdr) * CUDBG_MAX_ENTITY;
+ len += CUDBG_DUMP_BUFF_SIZE;
+
+ data->size = len;
+ strncpy(data->note_name, CXGB4_VMCOREDD_NOTE_NAME,
+ sizeof(data->note_name));
+ snprintf(data->dump_name, sizeof(data->dump_name), "%s_%s",
+ cxgb4_driver_name, adap->name);
+ data->vmcoredd_callback = cxgb4_cudbg_vmcoredd_collect;
+
+ return vmcore_add_device_dump(data);
+}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h
index ce1ac9a1c878..eea246761679 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h
@@ -41,8 +41,12 @@ enum CXGB4_ETHTOOL_DUMP_FLAGS {
CXGB4_ETH_DUMP_HW = (1 << 1), /* various FW and HW dumps */
};
+#define CXGB4_VMCOREDD_NOTE_NAME "CHELSIO"
+#define CXGB4_ETH_DUMP_ALL (CXGB4_ETH_DUMP_MEM | CXGB4_ETH_DUMP_HW)
+
u32 cxgb4_get_dump_length(struct adapter *adap, u32 flag);
int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
u32 flag);
void cxgb4_init_ethtool_dump(struct adapter *adapter);
+int cxgb4_cudbg_vmcore_add_dump(struct adapter *adap);
#endif /* __CXGB4_CUDBG_H__ */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 24d2865b8806..32cad0acf76c 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -5544,6 +5544,16 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto out_free_adapter;
+ if (is_kdump_kernel()) {
+ /* Collect hardware state and append to /proc/vmcore */
+ err = cxgb4_cudbg_vmcore_add_dump(adapter);
+ if (err) {
+ dev_warn(adapter->pdev_dev,
+ "Fail collecting vmcore device dump, err: %d. Continuing\n",
+ err);
+ err = 0;
+ }
+ }
if (!is_t4(adapter->params.chip)) {
s_qpp = (QUEUESPERPAGEPF0_S +
--
2.14.1
^ permalink raw reply related
* [PATCH net-next v6 2/3] vmcore: append device dumps to vmcore as elf notes
From: Rahul Lakkireddy @ 2018-04-30 10:13 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA,
kexec-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: indranil-ut6Up61K2wZBDgjK7y7TUQ, nirranjan-ut6Up61K2wZBDgjK7y7TUQ,
stephen-OTpzqLSitTUnbdJkjeBofR2eb7JE58TQ,
ganeshgr-ut6Up61K2wZBDgjK7y7TUQ, Rahul Lakkireddy,
ebiederm-aS9lmoZGLiVWk0Htik3J/w,
akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
torvalds-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
davem-fT/PcQaiUtIeIZ0/mPfg9Q,
viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn
In-Reply-To: <cover.1525082669.git.rahul.lakkireddy-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
Update read and mmap logic to append device dumps as additional notes
before the other elf notes. We add device dumps before other elf notes
because the other elf notes may not fill the elf notes buffer
completely and we will end up with zero-filled data between the elf
notes and the device dumps. Tools will then try to decode this
zero-filled data as valid notes and we don't want that. Hence, adding
device dumps before the other elf notes ensure that zero-filled data
can be avoided. This also ensures that the device dumps and the
other elf notes can be properly mmaped at page aligned address.
Incorporate device dump size into the total vmcore size. Also update
offsets for other program headers after the device dumps are added.
Suggested-by: Eric Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>.
Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Ganesh Goudar <ganeshgr-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
---
v6:
- No changes.
v5:
- No changes.
v4:
- No changes.
v3:
- Patch added in this version.
- Exported dumps as elf notes. Suggested by Eric Biederman
<ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>.
fs/proc/vmcore.c | 247 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 243 insertions(+), 4 deletions(-)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 2392be007228..7c6b5ca70056 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -39,6 +39,8 @@ static size_t elfcorebuf_sz_orig;
static char *elfnotes_buf;
static size_t elfnotes_sz;
+/* Size of all notes minus the device dump notes */
+static size_t elfnotes_orig_sz;
/* Total size of vmcore file. */
static u64 vmcore_size;
@@ -51,6 +53,9 @@ static LIST_HEAD(vmcoredd_list);
static DEFINE_MUTEX(vmcoredd_mutex);
#endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
+/* Device Dump Size */
+static size_t vmcoredd_orig_sz;
+
/*
* Returns > 0 for RAM pages, 0 for non-RAM pages, < 0 on error
* The called function has to take care of module refcounting.
@@ -185,6 +190,77 @@ static int copy_to(void *target, void *src, size_t size, int userbuf)
return 0;
}
+#ifdef CONFIG_PROC_VMCORE_DEVICE_DUMP
+static int vmcoredd_copy_dumps(void *dst, u64 start, size_t size, int userbuf)
+{
+ struct vmcoredd_node *dump;
+ u64 offset = 0;
+ int ret = 0;
+ size_t tsz;
+ char *buf;
+
+ mutex_lock(&vmcoredd_mutex);
+ list_for_each_entry(dump, &vmcoredd_list, list) {
+ if (start < offset + dump->size) {
+ tsz = min(offset + (u64)dump->size - start, (u64)size);
+ buf = dump->buf + start - offset;
+ if (copy_to(dst, buf, tsz, userbuf)) {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+
+ size -= tsz;
+ start += tsz;
+ dst += tsz;
+
+ /* Leave now if buffer filled already */
+ if (!size)
+ goto out_unlock;
+ }
+ offset += dump->size;
+ }
+
+out_unlock:
+ mutex_unlock(&vmcoredd_mutex);
+ return ret;
+}
+
+static int vmcoredd_mmap_dumps(struct vm_area_struct *vma, unsigned long dst,
+ u64 start, size_t size)
+{
+ struct vmcoredd_node *dump;
+ u64 offset = 0;
+ int ret = 0;
+ size_t tsz;
+ char *buf;
+
+ mutex_lock(&vmcoredd_mutex);
+ list_for_each_entry(dump, &vmcoredd_list, list) {
+ if (start < offset + dump->size) {
+ tsz = min(offset + (u64)dump->size - start, (u64)size);
+ buf = dump->buf + start - offset;
+ if (remap_vmalloc_range_partial(vma, dst, buf, tsz)) {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+
+ size -= tsz;
+ start += tsz;
+ dst += tsz;
+
+ /* Leave now if buffer filled already */
+ if (!size)
+ goto out_unlock;
+ }
+ offset += dump->size;
+ }
+
+out_unlock:
+ mutex_unlock(&vmcoredd_mutex);
+ return ret;
+}
+#endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
+
/* Read from the ELF header and then the crash dump. On error, negative value is
* returned otherwise number of bytes read are returned.
*/
@@ -222,10 +298,41 @@ static ssize_t __read_vmcore(char *buffer, size_t buflen, loff_t *fpos,
if (*fpos < elfcorebuf_sz + elfnotes_sz) {
void *kaddr;
+ /* We add device dumps before other elf notes because the
+ * other elf notes may not fill the elf notes buffer
+ * completely and we will end up with zero-filled data
+ * between the elf notes and the device dumps. Tools will
+ * then try to decode this zero-filled data as valid notes
+ * and we don't want that. Hence, adding device dumps before
+ * the other elf notes ensure that zero-filled data can be
+ * avoided.
+ */
+#ifdef CONFIG_PROC_VMCORE_DEVICE_DUMP
+ /* Read device dumps */
+ if (*fpos < elfcorebuf_sz + vmcoredd_orig_sz) {
+ tsz = min(elfcorebuf_sz + vmcoredd_orig_sz -
+ (size_t)*fpos, buflen);
+ start = *fpos - elfcorebuf_sz;
+ if (vmcoredd_copy_dumps(buffer, start, tsz, userbuf))
+ return -EFAULT;
+
+ buflen -= tsz;
+ *fpos += tsz;
+ buffer += tsz;
+ acc += tsz;
+
+ /* leave now if filled buffer already */
+ if (!buflen)
+ return acc;
+ }
+#endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
+
+ /* Read remaining elf notes */
tsz = min(elfcorebuf_sz + elfnotes_sz - (size_t)*fpos, buflen);
- kaddr = elfnotes_buf + *fpos - elfcorebuf_sz;
+ kaddr = elfnotes_buf + *fpos - elfcorebuf_sz - vmcoredd_orig_sz;
if (copy_to(buffer, kaddr, tsz, userbuf))
return -EFAULT;
+
buflen -= tsz;
*fpos += tsz;
buffer += tsz;
@@ -451,11 +558,46 @@ static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
if (start < elfcorebuf_sz + elfnotes_sz) {
void *kaddr;
+ /* We add device dumps before other elf notes because the
+ * other elf notes may not fill the elf notes buffer
+ * completely and we will end up with zero-filled data
+ * between the elf notes and the device dumps. Tools will
+ * then try to decode this zero-filled data as valid notes
+ * and we don't want that. Hence, adding device dumps before
+ * the other elf notes ensure that zero-filled data can be
+ * avoided. This also ensures that the device dumps and
+ * other elf notes can be properly mmaped at page aligned
+ * address.
+ */
+#ifdef CONFIG_PROC_VMCORE_DEVICE_DUMP
+ /* Read device dumps */
+ if (start < elfcorebuf_sz + vmcoredd_orig_sz) {
+ u64 start_off;
+
+ tsz = min(elfcorebuf_sz + vmcoredd_orig_sz -
+ (size_t)start, size);
+ start_off = start - elfcorebuf_sz;
+ if (vmcoredd_mmap_dumps(vma, vma->vm_start + len,
+ start_off, tsz))
+ goto fail;
+
+ size -= tsz;
+ start += tsz;
+ len += tsz;
+
+ /* leave now if filled buffer already */
+ if (!size)
+ return 0;
+ }
+#endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
+
+ /* Read remaining elf notes */
tsz = min(elfcorebuf_sz + elfnotes_sz - (size_t)start, size);
- kaddr = elfnotes_buf + start - elfcorebuf_sz;
+ kaddr = elfnotes_buf + start - elfcorebuf_sz - vmcoredd_orig_sz;
if (remap_vmalloc_range_partial(vma, vma->vm_start + len,
kaddr, tsz))
goto fail;
+
size -= tsz;
start += tsz;
len += tsz;
@@ -703,6 +845,11 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
/* Modify e_phnum to reflect merged headers. */
ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
+ /* Store the size of all notes. We need this to update the note
+ * header when the device dumps will be added.
+ */
+ elfnotes_orig_sz = phdr.p_memsz;
+
return 0;
}
@@ -889,6 +1036,11 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
/* Modify e_phnum to reflect merged headers. */
ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
+ /* Store the size of all notes. We need this to update the note
+ * header when the device dumps will be added.
+ */
+ elfnotes_orig_sz = phdr.p_memsz;
+
return 0;
}
@@ -981,8 +1133,8 @@ static int __init process_ptload_program_headers_elf32(char *elfptr,
}
/* Sets offset fields of vmcore elements. */
-static void __init set_vmcore_list_offsets(size_t elfsz, size_t elfnotes_sz,
- struct list_head *vc_list)
+static void set_vmcore_list_offsets(size_t elfsz, size_t elfnotes_sz,
+ struct list_head *vc_list)
{
loff_t vmcore_off;
struct vmcore *m;
@@ -1201,6 +1353,92 @@ static void vmcoredd_write_note(void *buf, struct vmcoredd_data *data,
memcpy(note_ptr, &vdd_hdr, sizeof(vdd_hdr));
}
+/**
+ * vmcoredd_update_program_headers - Update all Elf program headers
+ * @elfptr: Pointer to elf header
+ * @elfnotesz: Size of elf notes aligned to page size
+ * @vmcoreddsz: Size of device dumps to be added to elf note header
+ *
+ * Determine type of Elf header (Elf64 or Elf32) and update the elf note size.
+ * Also update the offsets of all the program headers after the elf note header.
+ */
+static void vmcoredd_update_program_headers(char *elfptr, size_t elfnotesz,
+ size_t vmcoreddsz)
+{
+ unsigned char *e_ident = (unsigned char *)elfptr;
+ u64 start, end, size;
+ loff_t vmcore_off;
+ u32 i;
+
+ vmcore_off = elfcorebuf_sz + elfnotesz;
+
+ if (e_ident[EI_CLASS] == ELFCLASS64) {
+ Elf64_Ehdr *ehdr = (Elf64_Ehdr *)elfptr;
+ Elf64_Phdr *phdr = (Elf64_Phdr *)(elfptr + sizeof(Elf64_Ehdr));
+
+ /* Update all program headers */
+ for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+ if (phdr->p_type == PT_NOTE) {
+ /* Update note size */
+ phdr->p_memsz = elfnotes_orig_sz + vmcoreddsz;
+ phdr->p_filesz = phdr->p_memsz;
+ continue;
+ }
+
+ start = rounddown(phdr->p_offset, PAGE_SIZE);
+ end = roundup(phdr->p_offset + phdr->p_memsz,
+ PAGE_SIZE);
+ size = end - start;
+ phdr->p_offset = vmcore_off + (phdr->p_offset - start);
+ vmcore_off += size;
+ }
+ } else {
+ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfptr;
+ Elf32_Phdr *phdr = (Elf32_Phdr *)(elfptr + sizeof(Elf32_Ehdr));
+
+ /* Update all program headers */
+ for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+ if (phdr->p_type == PT_NOTE) {
+ /* Update note size */
+ phdr->p_memsz = elfnotes_orig_sz + vmcoreddsz;
+ phdr->p_filesz = phdr->p_memsz;
+ continue;
+ }
+
+ start = rounddown(phdr->p_offset, PAGE_SIZE);
+ end = roundup(phdr->p_offset + phdr->p_memsz,
+ PAGE_SIZE);
+ size = end - start;
+ phdr->p_offset = vmcore_off + (phdr->p_offset - start);
+ vmcore_off += size;
+ }
+ }
+}
+
+/**
+ * vmcoredd_update_size - Update the total size of the device dumps and update
+ * Elf header
+ * @dump_size: Size of the current device dump to be added to total size
+ *
+ * Update the total size of all the device dumps and update the Elf program
+ * headers. Calculate the new offsets for the vmcore list and update the
+ * total vmcore size.
+ */
+static void vmcoredd_update_size(size_t dump_size)
+{
+ vmcoredd_orig_sz += dump_size;
+ elfnotes_sz = roundup(elfnotes_orig_sz, PAGE_SIZE) + vmcoredd_orig_sz;
+ vmcoredd_update_program_headers(elfcorebuf, elfnotes_sz,
+ vmcoredd_orig_sz);
+
+ /* Update vmcore list offsets */
+ set_vmcore_list_offsets(elfcorebuf_sz, elfnotes_sz, &vmcore_list);
+
+ vmcore_size = get_vmcore_size(elfcorebuf_sz, elfnotes_sz,
+ &vmcore_list);
+ proc_vmcore->size = vmcore_size;
+}
+
/**
* vmcore_add_device_dump - Add a buffer containing device dump to vmcore
* @data: dump info.
@@ -1255,6 +1493,7 @@ static int __vmcore_add_device_dump(struct vmcoredd_data *data)
list_add_tail(&dump->list, &vmcoredd_list);
mutex_unlock(&vmcoredd_mutex);
+ vmcoredd_update_size(data_size);
return 0;
out_err:
--
2.14.1
^ permalink raw reply related
* [PATCH net-next v6 1/3] vmcore: add API to collect hardware dump in second kernel
From: Rahul Lakkireddy @ 2018-04-30 10:13 UTC (permalink / raw)
To: netdev, kexec, linux-fsdevel, linux-kernel
Cc: davem, viro, ebiederm, stephen, akpm, torvalds, ganeshgr,
nirranjan, indranil, Rahul Lakkireddy
In-Reply-To: <cover.1525082669.git.rahul.lakkireddy@chelsio.com>
The sequence of actions done by device drivers to append their device
specific hardware/firmware logs to /proc/vmcore are as follows:
1. During probe (before hardware is initialized), device drivers
register to the vmcore module (via vmcore_add_device_dump()), with
callback function, along with buffer size and log name needed for
firmware/hardware log collection.
2. vmcore module allocates the buffer with requested size. It adds
an Elf note and invokes the device driver's registered callback
function.
3. Device driver collects all hardware/firmware logs into the buffer
and returns control back to vmcore module.
Ensure that the device dump buffer size is always aligned to page size
so that it can be mmaped.
Also, rename alloc_elfnotes_buf() to vmcore_alloc_buf() to make it more
generic and reserve NT_VMCOREDD note type to indicate vmcore device
dump.
Suggested-by: Eric Biederman <ebiederm@xmission.com>.
Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
---
v6:
- Reworked device dump elf note name to contain vendor identifier.
- Added vmcoredd_header that precedes actual dump in the Elf Note.
- Device dump's name is moved inside vmcoredd_header.
v5:
- Removed enabling CONFIG_PROC_VMCORE_DEVICE_DUMP by default and
updated help message to indicate that the driver must be present
in second kernel's initramfs to collect the underlying device
snapshot.
v4:
- Made __vmcore_add_device_dump() static.
- Moved compile check to define vmcore_add_device_dump() to
crash_dump.h to fix compilation when vmcore.c is not compiled in.
- Convert ---help--- to help in Kconfig as indicated by checkpatch.
- Rebased to tip.
v3:
- Dropped sysfs crashdd module.
- Added CONFIG_PROC_VMCORE_DEVICE_DUMP to allow configuring device
dump support.
- Moved logic related to adding dumps from crashdd to vmcore module.
- Rename all crashdd* to vmcoredd*.
v2:
- Added ABI Documentation for crashdd.
- Directly use octal permission instead of macro.
Changes since rfc v2:
- Moved exporting crashdd from procfs to sysfs. Suggested by
Stephen Hemminger <stephen@networkplumber.org>
- Moved code from fs/proc/crashdd.c to fs/crashdd/ directory.
- Replaced all proc API with sysfs API and updated comments.
- Calling driver callback before creating the binary file under
crashdd sysfs.
- Changed binary dump file permission from S_IRUSR to S_IRUGO.
- Changed module name from CRASH_DRIVER_DUMP to CRASH_DEVICE_DUMP.
rfc v2:
- Collecting logs in 2nd kernel instead of during kernel panic.
Suggested by Eric Biederman <ebiederm@xmission.com>.
- Patch added in this series.
fs/proc/Kconfig | 15 ++++
fs/proc/vmcore.c | 168 ++++++++++++++++++++++++++++++++++++++++++---
include/linux/crash_core.h | 10 +++
include/linux/crash_dump.h | 18 +++++
include/linux/kcore.h | 6 ++
include/uapi/linux/elf.h | 1 +
6 files changed, 209 insertions(+), 9 deletions(-)
diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig
index 1ade1206bb89..0eaeb41453f5 100644
--- a/fs/proc/Kconfig
+++ b/fs/proc/Kconfig
@@ -43,6 +43,21 @@ config PROC_VMCORE
help
Exports the dump image of crashed kernel in ELF format.
+config PROC_VMCORE_DEVICE_DUMP
+ bool "Device Hardware/Firmware Log Collection"
+ depends on PROC_VMCORE
+ default n
+ help
+ After kernel panic, device drivers can collect the device
+ specific snapshot of their hardware or firmware before the
+ underlying devices are initialized in crash recovery kernel.
+ Note that the device driver must be present in the crash
+ recovery kernel's initramfs to collect its underlying device
+ snapshot.
+
+ If you say Y here, the collected device dumps will be added
+ as ELF notes to /proc/vmcore.
+
config PROC_SYSCTL
bool "Sysctl support (/proc/sys)" if EXPERT
depends on PROC_FS
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index a45f0af22a60..2392be007228 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -20,6 +20,7 @@
#include <linux/init.h>
#include <linux/crash_dump.h>
#include <linux/list.h>
+#include <linux/mutex.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
#include <linux/uaccess.h>
@@ -44,6 +45,12 @@ static u64 vmcore_size;
static struct proc_dir_entry *proc_vmcore;
+#ifdef CONFIG_PROC_VMCORE_DEVICE_DUMP
+/* Device Dump list and mutex to synchronize access to list */
+static LIST_HEAD(vmcoredd_list);
+static DEFINE_MUTEX(vmcoredd_mutex);
+#endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
+
/*
* Returns > 0 for RAM pages, 0 for non-RAM pages, < 0 on error
* The called function has to take care of module refcounting.
@@ -302,10 +309,8 @@ static const struct vm_operations_struct vmcore_mmap_ops = {
};
/**
- * alloc_elfnotes_buf - allocate buffer for ELF note segment in
- * vmalloc memory
- *
- * @notes_sz: size of buffer
+ * vmcore_alloc_buf - allocate buffer in vmalloc memory
+ * @sizez: size of buffer
*
* If CONFIG_MMU is defined, use vmalloc_user() to allow users to mmap
* the buffer to user-space by means of remap_vmalloc_range().
@@ -313,12 +318,12 @@ static const struct vm_operations_struct vmcore_mmap_ops = {
* If CONFIG_MMU is not defined, use vzalloc() since mmap_vmcore() is
* disabled and there's no need to allow users to mmap the buffer.
*/
-static inline char *alloc_elfnotes_buf(size_t notes_sz)
+static inline char *vmcore_alloc_buf(size_t size)
{
#ifdef CONFIG_MMU
- return vmalloc_user(notes_sz);
+ return vmalloc_user(size);
#else
- return vzalloc(notes_sz);
+ return vzalloc(size);
#endif
}
@@ -665,7 +670,7 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
return rc;
*notes_sz = roundup(phdr_sz, PAGE_SIZE);
- *notes_buf = alloc_elfnotes_buf(*notes_sz);
+ *notes_buf = vmcore_alloc_buf(*notes_sz);
if (!*notes_buf)
return -ENOMEM;
@@ -851,7 +856,7 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
return rc;
*notes_sz = roundup(phdr_sz, PAGE_SIZE);
- *notes_buf = alloc_elfnotes_buf(*notes_sz);
+ *notes_buf = vmcore_alloc_buf(*notes_sz);
if (!*notes_buf)
return -ENOMEM;
@@ -1145,6 +1150,148 @@ static int __init parse_crash_elf_headers(void)
return 0;
}
+#ifdef CONFIG_PROC_VMCORE_DEVICE_DUMP
+/**
+ * vmcoredd_get_note_size - Get size of the note that will be inserted at
+ * beginning of the dump's buffer.
+ * @name: Note's name
+ *
+ * Gets the overall size of the note that will be inserted at the beginning
+ * of the dump's buffer. It also adds padding, if necessary to meet
+ * alignment requirements.
+ */
+static inline size_t vmcoredd_get_note_size(const char *name)
+{
+ /* Must include '\0' and hence the extra +1 */
+ return CRASH_CORE_NOTE_HEAD_BYTES +
+ ALIGN(strlen(name) + 1, sizeof(Elf_Word));
+}
+
+/**
+ * vmcoredd_write_note - Write note at the beginning of the dump's buffer
+ * @buf: Output buffer where the note is written
+ * @data: Dump info
+ * @size: Size of the dump including vmcore device dump header
+ *
+ * Fills beginning of the dump's data with elf note and vmcore device dump
+ * header.
+ */
+static void vmcoredd_write_note(void *buf, struct vmcoredd_data *data,
+ size_t size)
+{
+ struct elf_note *note = (struct elf_note *)buf;
+ struct vmcoredd_header vdd_hdr = { 0 };
+ u8 *note_ptr = buf;
+
+ vdd_hdr.header_len = sizeof(struct vmcoredd_header);
+ vdd_hdr.data_len = data->size;
+ strncpy(vdd_hdr.dump_name, data->dump_name, sizeof(vdd_hdr.dump_name));
+
+ note->n_namesz = vmcoredd_get_note_size(data->note_name) -
+ CRASH_CORE_NOTE_HEAD_BYTES;
+ note->n_descsz = size;
+ note->n_type = NT_VMCOREDD;
+
+ /* Write note name */
+ note_ptr += CRASH_CORE_NOTE_HEAD_BYTES;
+ strncpy((char *)note_ptr, data->note_name, note->n_namesz);
+
+ /* Write vmcore device dump header */
+ note_ptr += note->n_namesz;
+ memcpy(note_ptr, &vdd_hdr, sizeof(vdd_hdr));
+}
+
+/**
+ * vmcore_add_device_dump - Add a buffer containing device dump to vmcore
+ * @data: dump info.
+ *
+ * Allocate a buffer and invoke the calling driver's dump collect routine.
+ * Write Elf note at the beginning of the buffer to indicate vmcore device
+ * dump and add the dump to global list.
+ */
+static int __vmcore_add_device_dump(struct vmcoredd_data *data)
+{
+ size_t note_size, data_size;
+ struct vmcoredd_node *dump;
+ void *buf = NULL;
+ int ret;
+
+ if (!data || !strlen(data->note_name) ||
+ !strlen(data->dump_name) ||
+ !data->vmcoredd_callback || !data->size)
+ return -EINVAL;
+
+ dump = vzalloc(sizeof(*dump));
+ if (!dump) {
+ ret = -ENOMEM;
+ goto out_err;
+ }
+
+ note_size = vmcoredd_get_note_size(data->note_name);
+ /* Keep size of the buffer page aligned so that it can be mmaped */
+ data_size = roundup(note_size + sizeof(struct vmcoredd_header) +
+ data->size, PAGE_SIZE);
+
+ /* Allocate buffer for driver's to write their dumps */
+ buf = vmcore_alloc_buf(data_size);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto out_err;
+ }
+
+ vmcoredd_write_note(buf, data, data_size - note_size);
+
+ /* Invoke the driver's dump collection routing */
+ ret = data->vmcoredd_callback(data, buf + note_size +
+ sizeof(struct vmcoredd_header));
+ if (ret)
+ goto out_err;
+
+ dump->buf = buf;
+ dump->size = data_size;
+
+ /* Add the dump to driver sysfs list */
+ mutex_lock(&vmcoredd_mutex);
+ list_add_tail(&dump->list, &vmcoredd_list);
+ mutex_unlock(&vmcoredd_mutex);
+
+ return 0;
+
+out_err:
+ if (buf)
+ vfree(buf);
+
+ if (dump)
+ vfree(dump);
+
+ return ret;
+}
+
+int vmcore_add_device_dump(struct vmcoredd_data *data)
+{
+ return __vmcore_add_device_dump(data);
+}
+EXPORT_SYMBOL(vmcore_add_device_dump);
+#endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
+
+/* Free all dumps in vmcore device dump list */
+static void vmcore_free_device_dumps(void)
+{
+#ifdef CONFIG_PROC_VMCORE_DEVICE_DUMP
+ mutex_lock(&vmcoredd_mutex);
+ while (!list_empty(&vmcoredd_list)) {
+ struct vmcoredd_node *dump;
+
+ dump = list_first_entry(&vmcoredd_list, struct vmcoredd_node,
+ list);
+ list_del(&dump->list);
+ vfree(dump->buf);
+ vfree(dump);
+ }
+ mutex_unlock(&vmcoredd_mutex);
+#endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
+}
+
/* Init function for vmcore module. */
static int __init vmcore_init(void)
{
@@ -1192,4 +1339,7 @@ void vmcore_cleanup(void)
kfree(m);
}
free_elfcorebuf();
+
+ /* clear vmcore device dump list */
+ vmcore_free_device_dumps();
}
diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
index b511f6d24b42..e38c5dbe3016 100644
--- a/include/linux/crash_core.h
+++ b/include/linux/crash_core.h
@@ -27,6 +27,16 @@
VMCOREINFO_NOTE_NAME_BYTES + \
VMCOREINFO_BYTES)
+#define VMCOREDD_MAX_NAME_BYTES 32
+
+struct vmcoredd_header {
+ unsigned int header_len; /* Length of this header */
+ unsigned int reserved;
+ unsigned long data_len; /* Length of the device dump */
+ char dump_name[VMCOREDD_MAX_NAME_BYTES]; /* Name of the device dump */
+ unsigned char reserved2[16];
+};
+
typedef u32 note_buf_t[CRASH_CORE_NOTE_BYTES/4];
void crash_update_vmcoreinfo_safecopy(void *ptr);
diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
index f7ac2aa93269..45ce7ca4625a 100644
--- a/include/linux/crash_dump.h
+++ b/include/linux/crash_dump.h
@@ -93,4 +93,22 @@ static inline bool is_kdump_kernel(void) { return 0; }
#endif /* CONFIG_CRASH_DUMP */
extern unsigned long saved_max_pfn;
+
+/* Device Dump information to be filled by drivers */
+struct vmcoredd_data {
+ char note_name[VMCOREDD_MAX_NAME_BYTES]; /* Name of the Elf note */
+ char dump_name[VMCOREDD_MAX_NAME_BYTES]; /* Unique name of the dump */
+ unsigned long size; /* Size of the dump */
+ /* Driver's registered callback to be invoked to collect dump */
+ int (*vmcoredd_callback)(struct vmcoredd_data *data, void *buf);
+};
+
+#ifdef CONFIG_PROC_VMCORE_DEVICE_DUMP
+int vmcore_add_device_dump(struct vmcoredd_data *data);
+#else
+static inline int vmcore_add_device_dump(struct vmcoredd_data *data)
+{
+ return -EOPNOTSUPP;
+}
+#endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
#endif /* LINUX_CRASHDUMP_H */
diff --git a/include/linux/kcore.h b/include/linux/kcore.h
index 80db19d3a505..aa26e7199060 100644
--- a/include/linux/kcore.h
+++ b/include/linux/kcore.h
@@ -28,6 +28,12 @@ struct vmcore {
loff_t offset;
};
+struct vmcoredd_node {
+ struct list_head list; /* List of dumps */
+ void *buf; /* Buffer containing device's dump */
+ unsigned long size; /* Size of the buffer */
+};
+
#ifdef CONFIG_PROC_KCORE
extern void kclist_add(struct kcore_list *, void *, size_t, int type);
#else
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index e2535d6dcec7..4e12c423b9fe 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -421,6 +421,7 @@ typedef struct elf64_shdr {
#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
#define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension registers */
#define NT_ARC_V2 0x600 /* ARCv2 accumulator/extra registers */
+#define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note */
/* Note header in a PT_NOTE section */
typedef struct elf32_note {
--
2.14.1
^ permalink raw reply related
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