* Re: [PATCH net] net: sched: fix NULL pointer dereference when action calls some targets
From: Xin Long @ 2017-08-16 8:39 UTC (permalink / raw)
To: Cong Wang; +Cc: network dev, David Miller, netfilter-devel, Jamal Hadi Salim
In-Reply-To: <CAM_iQpXbtHDxVjZ=DoTiLXHLQy6q=JVBa66EqSOy95ZbFg-wkQ@mail.gmail.com>
On Wed, Aug 9, 2017 at 7:33 AM, Cong Wang <xiyou.wangcong@gmail.com> wrote:
> On Mon, Aug 7, 2017 at 7:33 PM, Xin Long <lucien.xin@gmail.com> wrote:
>> On Tue, Aug 8, 2017 at 9:15 AM, Cong Wang <xiyou.wangcong@gmail.com> wrote:
>>> This looks like a completely API burden?
>> netfilter xt targets are not really compatible with netsched action.
>> I've got to say, the patch is just a way to make checkentry return
>> false and avoid panic. like [1] said
>
> I don't doubt you fix a crash, I am thinking if we can
> "fix" the API instead of fixing the caller.
Hi, Cong,
For now, I don't think it's possible to change APIs or some of their targets
for the panic caused by action xt calling.
The common way should be fixed in net_sched side.
Given that the issue is very easy to triggered,
let's wait for netfilter's replies for another few days,
otherwise I will repost the fix, agree ?
>
> I am not familiar with this API, so just my 2 cents...
^ permalink raw reply
* Re: [patch net-next 0/3] net/sched: Improve getting objects by indexes
From: Jiri Pirko @ 2017-08-16 8:39 UTC (permalink / raw)
To: Christian König; +Cc: Chris Mi, netdev
In-Reply-To: <e3cb8f8e-7808-48b4-d90d-67f30ab39687@amd.com>
Wed, Aug 16, 2017 at 10:31:35AM CEST, christian.koenig@amd.com wrote:
>Am 16.08.2017 um 10:16 schrieb Jiri Pirko:
>> Wed, Aug 16, 2017 at 09:49:07AM CEST, christian.koenig@amd.com wrote:
>> > Am 16.08.2017 um 04:12 schrieb Chris Mi:
>> > > Using current TC code, it is very slow to insert a lot of rules.
>> > >
>> > > In order to improve the rules update rate in TC,
>> > > we introduced the following two changes:
>> > > 1) changed cls_flower to use IDR to manage the filters.
>> > > 2) changed all act_xxx modules to use IDR instead of
>> > > a small hash table
>> > >
>> > > But IDR has a limitation that it uses int. TC handle uses u32.
>> > > To make sure there is no regression, we also changed IDR to use
>> > > unsigned long. All clients of IDR are changed to use new IDR API.
>> > WOW, wait a second. The idr change is touching a lot of drivers and to be
>> > honest doesn't looks correct at all.
>> >
>> > Just look at the first chunk of your modification:
>> > > @@ -998,8 +999,9 @@ int bsg_register_queue(struct request_queue *q, struct device *parent,
>> > > mutex_lock(&bsg_mutex);
>> > > - ret = idr_alloc(&bsg_minor_idr, bcd, 0, BSG_MAX_DEVS, GFP_KERNEL);
>> > > - if (ret < 0) {
>> > > + ret = idr_alloc(&bsg_minor_idr, bcd, &idr_index, 0, BSG_MAX_DEVS,
>> > > + GFP_KERNEL);
>> > > + if (ret) {
>> > > if (ret == -ENOSPC) {
>> > > printk(KERN_ERR "bsg: too many bsg devices\n");
>> > > ret = -EINVAL;
>> > The condition "if (ret)" will now always be true after the first allocation
>> > and so we always run into the error handling after that.
>> On success, idr_alloc returns 0.
>
>Ah, I see. You change the idr_alloc to return the resulting index as separate
>parameter.
>
>You should explicit note that in the commit message, cause that is something
>easily overlooked.
>
>In general I strongly suggest to add a separate interface for allocating
>unsigned long handles, use that for the while being and then move the
>existing drivers over bit by bit.
>
>A single patch which touches so many different driver is practically
>impossible to review consequently.
Understood. I think is is good to avoid having some "idr_alloc2". That
is why I suggested to do this in one go, to avoid "idr_alloc2" and then
patch to rename "idr_alloc2" to "idr_alloc" once nobody uses the original
"idr_alloc". In fact, if you do it driver, by driver, the review burden
would be the same, probably even bigger, you'll just have 100+ patches.
Why would it help?
I believe that the changes in drivers are trivial enough to have it in
one patch.
>
>> > I've never read the bsg code before, but that's certainly not correct. And
>> > that incorrect pattern repeats over and over again in this code.
>> >
>> > Apart from that why the heck do you want to allocate more than 1<<31 handles?
>> tc action indexes for example. That is part of this patchset.
>
>Well, let me refine the question: Why does tc action indexes need more than
>31 bits? From an outside view that looks like pure overkill.
That is current state, uapi. We have to live with it.
^ permalink raw reply
* Re: [patch net-next 0/3] net/sched: Improve getting objects by indexes
From: Christian König @ 2017-08-16 8:31 UTC (permalink / raw)
To: Jiri Pirko; +Cc: Chris Mi, netdev
In-Reply-To: <20170816081631.GC1868@nanopsycho>
Am 16.08.2017 um 10:16 schrieb Jiri Pirko:
> Wed, Aug 16, 2017 at 09:49:07AM CEST, christian.koenig@amd.com wrote:
>> Am 16.08.2017 um 04:12 schrieb Chris Mi:
>>> Using current TC code, it is very slow to insert a lot of rules.
>>>
>>> In order to improve the rules update rate in TC,
>>> we introduced the following two changes:
>>> 1) changed cls_flower to use IDR to manage the filters.
>>> 2) changed all act_xxx modules to use IDR instead of
>>> a small hash table
>>>
>>> But IDR has a limitation that it uses int. TC handle uses u32.
>>> To make sure there is no regression, we also changed IDR to use
>>> unsigned long. All clients of IDR are changed to use new IDR API.
>> WOW, wait a second. The idr change is touching a lot of drivers and to be
>> honest doesn't looks correct at all.
>>
>> Just look at the first chunk of your modification:
>>> @@ -998,8 +999,9 @@ int bsg_register_queue(struct request_queue *q, struct device *parent,
>>> mutex_lock(&bsg_mutex);
>>> - ret = idr_alloc(&bsg_minor_idr, bcd, 0, BSG_MAX_DEVS, GFP_KERNEL);
>>> - if (ret < 0) {
>>> + ret = idr_alloc(&bsg_minor_idr, bcd, &idr_index, 0, BSG_MAX_DEVS,
>>> + GFP_KERNEL);
>>> + if (ret) {
>>> if (ret == -ENOSPC) {
>>> printk(KERN_ERR "bsg: too many bsg devices\n");
>>> ret = -EINVAL;
>> The condition "if (ret)" will now always be true after the first allocation
>> and so we always run into the error handling after that.
> On success, idr_alloc returns 0.
Ah, I see. You change the idr_alloc to return the resulting index as
separate parameter.
You should explicit note that in the commit message, cause that is
something easily overlooked.
In general I strongly suggest to add a separate interface for allocating
unsigned long handles, use that for the while being and then move the
existing drivers over bit by bit.
A single patch which touches so many different driver is practically
impossible to review consequently.
>> I've never read the bsg code before, but that's certainly not correct. And
>> that incorrect pattern repeats over and over again in this code.
>>
>> Apart from that why the heck do you want to allocate more than 1<<31 handles?
> tc action indexes for example. That is part of this patchset.
Well, let me refine the question: Why does tc action indexes need more
than 31 bits? From an outside view that looks like pure overkill.
Regards,
Christian.
^ permalink raw reply
* Re: [PATCH] bpf: Update sysctl documentation to list all supported architectures
From: Daniel Borkmann @ 2017-08-16 8:18 UTC (permalink / raw)
To: Michael Ellerman, ast; +Cc: davem, netdev, linux-kernel
In-Reply-To: <1502860557-20247-1-git-send-email-mpe@ellerman.id.au>
Hi Michael,
On 08/16/2017 07:15 AM, Michael Ellerman wrote:
> The sysctl documentation states that the JIT is only available on
> x86_64, which is no longer correct.
>
> Update the list to include all architectures that enable HAVE_CBPF_JIT
> or HAVE_EBPF_JIT under some configuration.
>
> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Thanks for the patch!
> Documentation/sysctl/net.txt | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt
> index 14db18c970b1..f68356024d09 100644
> --- a/Documentation/sysctl/net.txt
> +++ b/Documentation/sysctl/net.txt
> @@ -36,8 +36,9 @@ bpf_jit_enable
> --------------
>
> This enables Berkeley Packet Filter Just in Time compiler.
> -Currently supported on x86_64 architecture, bpf_jit provides a framework
> -to speed packet filtering, the one used by tcpdump/libpcap for example.
> +Currently supported on arm, arm64, mips, powerpc, s390, sparc and x86_64
> +architectures, bpf_jit provides a framework to speed packet filtering, the one
> +used by tcpdump/libpcap for example.
Good point, could we actually make that as a bullet list and
differentiate between cBPF and eBPF JITs, so that a user doesn't
need to run git grep HAVE_{E,C}BPF_JIT to figure it out what the
switch enables on the arch used? That would be great.
So for eBPF JITs, we have covered:
* x86_64
* arm64
* ppc64
* sparc64
* mips64
For old cBPF, there is:
* arm
* mips
* ppc
* sparc
Thanks,
Daniel
> Values :
> 0 - disable the JIT (default value)
> 1 - enable the JIT
>
^ permalink raw reply
* Re: [patch net-next 0/3] net/sched: Improve getting objects by indexes
From: Jiri Pirko @ 2017-08-16 8:16 UTC (permalink / raw)
To: Christian König; +Cc: Chris Mi, netdev
In-Reply-To: <144b87a3-bbe4-a194-ed83-e54840d7c7c2@amd.com>
Wed, Aug 16, 2017 at 09:49:07AM CEST, christian.koenig@amd.com wrote:
>Am 16.08.2017 um 04:12 schrieb Chris Mi:
>> Using current TC code, it is very slow to insert a lot of rules.
>>
>> In order to improve the rules update rate in TC,
>> we introduced the following two changes:
>> 1) changed cls_flower to use IDR to manage the filters.
>> 2) changed all act_xxx modules to use IDR instead of
>> a small hash table
>>
>> But IDR has a limitation that it uses int. TC handle uses u32.
>> To make sure there is no regression, we also changed IDR to use
>> unsigned long. All clients of IDR are changed to use new IDR API.
>
>WOW, wait a second. The idr change is touching a lot of drivers and to be
>honest doesn't looks correct at all.
>
>Just look at the first chunk of your modification:
>> @@ -998,8 +999,9 @@ int bsg_register_queue(struct request_queue *q, struct device *parent,
>> mutex_lock(&bsg_mutex);
>> - ret = idr_alloc(&bsg_minor_idr, bcd, 0, BSG_MAX_DEVS, GFP_KERNEL);
>> - if (ret < 0) {
>> + ret = idr_alloc(&bsg_minor_idr, bcd, &idr_index, 0, BSG_MAX_DEVS,
>> + GFP_KERNEL);
>> + if (ret) {
>> if (ret == -ENOSPC) {
>> printk(KERN_ERR "bsg: too many bsg devices\n");
>> ret = -EINVAL;
>The condition "if (ret)" will now always be true after the first allocation
>and so we always run into the error handling after that.
On success, idr_alloc returns 0.
>
>I've never read the bsg code before, but that's certainly not correct. And
>that incorrect pattern repeats over and over again in this code.
>
>Apart from that why the heck do you want to allocate more than 1<<31 handles?
tc action indexes for example. That is part of this patchset.
^ permalink raw reply
* [patch net-next repost 2/3] net/sched: Change cls_flower to use IDR
From: Chris Mi @ 2017-08-16 8:14 UTC (permalink / raw)
To: netdev; +Cc: jhs, xiyou.wangcong, jiri, davem, mawilcox
In-Reply-To: <1502871244-19870-1-git-send-email-chrism@mellanox.com>
Currently, all filters with the same priority are linked in a doubly
linked list. Every filter should have a unique handle. To make the
handle unique, we need to iterate the list every time to see if the
handle exists or not when inserting a new filter. It is time-consuming.
For example, it takes about 5m3.169s to insert 64K rules.
This patch changes cls_flower to use IDR. With this patch, it
takes about 0m1.127s to insert 64K rules. The improvement is huge.
But please note that in this testing, all filters share the same action.
If every filter has a unique action, that is another bottleneck.
Follow-up patch in this patchset addresses that.
Signed-off-by: Chris Mi <chrism@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
net/sched/cls_flower.c | 55 +++++++++++++++++++++-----------------------------
1 file changed, 23 insertions(+), 32 deletions(-)
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index 052e902..071f0ef 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -68,7 +68,6 @@ struct cls_fl_head {
struct rhashtable ht;
struct fl_flow_mask mask;
struct flow_dissector dissector;
- u32 hgen;
bool mask_assigned;
struct list_head filters;
struct rhashtable_params ht_params;
@@ -76,6 +75,7 @@ struct cls_fl_head {
struct work_struct work;
struct rcu_head rcu;
};
+ struct idr handle_idr;
};
struct cls_fl_filter {
@@ -210,6 +210,7 @@ static int fl_init(struct tcf_proto *tp)
INIT_LIST_HEAD_RCU(&head->filters);
rcu_assign_pointer(tp->root, head);
+ idr_init(&head->handle_idr);
return 0;
}
@@ -295,6 +296,9 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f)
{
+ struct cls_fl_head *head = rtnl_dereference(tp->root);
+
+ idr_remove(&head->handle_idr, f->handle);
list_del_rcu(&f->list);
if (!tc_skip_hw(f->flags))
fl_hw_destroy_filter(tp, f);
@@ -327,6 +331,7 @@ static void fl_destroy(struct tcf_proto *tp)
list_for_each_entry_safe(f, next, &head->filters, list)
__fl_delete(tp, f);
+ idr_destroy(&head->handle_idr);
__module_get(THIS_MODULE);
call_rcu(&head->rcu, fl_destroy_rcu);
@@ -335,12 +340,8 @@ static void fl_destroy(struct tcf_proto *tp)
static void *fl_get(struct tcf_proto *tp, u32 handle)
{
struct cls_fl_head *head = rtnl_dereference(tp->root);
- struct cls_fl_filter *f;
- list_for_each_entry(f, &head->filters, list)
- if (f->handle == handle)
- return f;
- return NULL;
+ return idr_find(&head->handle_idr, handle);
}
static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
@@ -859,27 +860,6 @@ static int fl_set_parms(struct net *net, struct tcf_proto *tp,
return 0;
}
-static u32 fl_grab_new_handle(struct tcf_proto *tp,
- struct cls_fl_head *head)
-{
- unsigned int i = 0x80000000;
- u32 handle;
-
- do {
- if (++head->hgen == 0x7FFFFFFF)
- head->hgen = 1;
- } while (--i > 0 && fl_get(tp, head->hgen));
-
- if (unlikely(i == 0)) {
- pr_err("Insufficient number of handles\n");
- handle = 0;
- } else {
- handle = head->hgen;
- }
-
- return handle;
-}
-
static int fl_change(struct net *net, struct sk_buff *in_skb,
struct tcf_proto *tp, unsigned long base,
u32 handle, struct nlattr **tca,
@@ -890,6 +870,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
struct cls_fl_filter *fnew;
struct nlattr **tb;
struct fl_flow_mask mask = {};
+ unsigned long idr_index;
int err;
if (!tca[TCA_OPTIONS])
@@ -920,13 +901,21 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
goto errout;
if (!handle) {
- handle = fl_grab_new_handle(tp, head);
- if (!handle) {
- err = -EINVAL;
+ err = idr_alloc(&head->handle_idr, fnew, &idr_index,
+ 1, 0x80000000, GFP_KERNEL);
+ if (err)
goto errout;
- }
+ fnew->handle = idr_index;
+ }
+
+ /* user specifies a handle and it doesn't exist */
+ if (handle && !fold) {
+ err = idr_alloc(&head->handle_idr, fnew, &idr_index,
+ handle, handle + 1, GFP_KERNEL);
+ if (err)
+ goto errout;
+ fnew->handle = idr_index;
}
- fnew->handle = handle;
if (tb[TCA_FLOWER_FLAGS]) {
fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
@@ -980,6 +969,8 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
*arg = fnew;
if (fold) {
+ fnew->handle = handle;
+ idr_replace(&head->handle_idr, fnew, fnew->handle);
list_replace_rcu(&fold->list, &fnew->list);
tcf_unbind_filter(tp, &fold->res);
call_rcu(&fold->rcu, fl_destroy_filter);
--
1.8.3.1
^ permalink raw reply related
* [patch net-next repost 3/3] net/sched: Change act_api and act_xxx modules to use IDR
From: Chris Mi @ 2017-08-16 8:14 UTC (permalink / raw)
To: netdev; +Cc: jhs, xiyou.wangcong, jiri, davem, mawilcox
In-Reply-To: <1502871244-19870-1-git-send-email-chrism@mellanox.com>
Typically, each TC filter has its own action. All the actions of the
same type are saved in its hash table. But the hash buckets are too
small that it degrades to a list. And the performance is greatly
affected. For example, it takes about 0m11.914s to insert 64K rules.
If we convert the hash table to IDR, it only takes about 0m1.500s.
The improvement is huge.
But please note that the test result is based on previous patch that
cls_flower uses IDR.
Signed-off-by: Chris Mi <chrism@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
include/net/act_api.h | 76 +++++---------
net/sched/act_api.c | 249 ++++++++++++++++++++++-----------------------
net/sched/act_bpf.c | 17 ++--
net/sched/act_connmark.c | 16 ++-
net/sched/act_csum.c | 16 ++-
net/sched/act_gact.c | 16 ++-
net/sched/act_ife.c | 20 ++--
net/sched/act_ipt.c | 26 +++--
net/sched/act_mirred.c | 19 ++--
net/sched/act_nat.c | 16 ++-
net/sched/act_pedit.c | 18 ++--
net/sched/act_police.c | 18 ++--
net/sched/act_sample.c | 17 ++--
net/sched/act_simple.c | 20 ++--
net/sched/act_skbedit.c | 18 ++--
net/sched/act_skbmod.c | 18 ++--
net/sched/act_tunnel_key.c | 20 ++--
net/sched/act_vlan.c | 22 ++--
18 files changed, 277 insertions(+), 345 deletions(-)
diff --git a/include/net/act_api.h b/include/net/act_api.h
index 26ffd83..8f3d5d8 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -10,12 +10,9 @@
#include <net/net_namespace.h>
#include <net/netns/generic.h>
-
-struct tcf_hashinfo {
- struct hlist_head *htab;
- unsigned int hmask;
- spinlock_t lock;
- u32 index;
+struct tcf_idrinfo {
+ spinlock_t lock;
+ struct idr action_idr;
};
struct tc_action_ops;
@@ -25,9 +22,8 @@ struct tc_action {
__u32 type; /* for backward compat(TCA_OLD_COMPAT) */
__u32 order;
struct list_head list;
- struct tcf_hashinfo *hinfo;
+ struct tcf_idrinfo *idrinfo;
- struct hlist_node tcfa_head;
u32 tcfa_index;
int tcfa_refcnt;
int tcfa_bindcnt;
@@ -44,7 +40,6 @@ struct tc_action {
struct tc_cookie *act_cookie;
struct tcf_chain *goto_chain;
};
-#define tcf_head common.tcfa_head
#define tcf_index common.tcfa_index
#define tcf_refcnt common.tcfa_refcnt
#define tcf_bindcnt common.tcfa_bindcnt
@@ -57,27 +52,6 @@ struct tc_action {
#define tcf_lock common.tcfa_lock
#define tcf_rcu common.tcfa_rcu
-static inline unsigned int tcf_hash(u32 index, unsigned int hmask)
-{
- return index & hmask;
-}
-
-static inline int tcf_hashinfo_init(struct tcf_hashinfo *hf, unsigned int mask)
-{
- int i;
-
- spin_lock_init(&hf->lock);
- hf->index = 0;
- hf->hmask = mask;
- hf->htab = kzalloc((mask + 1) * sizeof(struct hlist_head),
- GFP_KERNEL);
- if (!hf->htab)
- return -ENOMEM;
- for (i = 0; i < mask + 1; i++)
- INIT_HLIST_HEAD(&hf->htab[i]);
- return 0;
-}
-
/* Update lastuse only if needed, to avoid dirtying a cache line.
* We use a temp variable to avoid fetching jiffies twice.
*/
@@ -126,53 +100,51 @@ struct tc_action_ops {
};
struct tc_action_net {
- struct tcf_hashinfo *hinfo;
+ struct tcf_idrinfo *idrinfo;
const struct tc_action_ops *ops;
};
static inline
int tc_action_net_init(struct tc_action_net *tn,
- const struct tc_action_ops *ops, unsigned int mask)
+ const struct tc_action_ops *ops)
{
int err = 0;
- tn->hinfo = kmalloc(sizeof(*tn->hinfo), GFP_KERNEL);
- if (!tn->hinfo)
+ tn->idrinfo = kmalloc(sizeof(*tn->idrinfo), GFP_KERNEL);
+ if (!tn->idrinfo)
return -ENOMEM;
tn->ops = ops;
- err = tcf_hashinfo_init(tn->hinfo, mask);
- if (err)
- kfree(tn->hinfo);
+ spin_lock_init(&tn->idrinfo->lock);
+ idr_init(&tn->idrinfo->action_idr);
return err;
}
-void tcf_hashinfo_destroy(const struct tc_action_ops *ops,
- struct tcf_hashinfo *hinfo);
+void tcf_idrinfo_destroy(const struct tc_action_ops *ops,
+ struct tcf_idrinfo *idrinfo);
static inline void tc_action_net_exit(struct tc_action_net *tn)
{
- tcf_hashinfo_destroy(tn->ops, tn->hinfo);
- kfree(tn->hinfo);
+ tcf_idrinfo_destroy(tn->ops, tn->idrinfo);
+ kfree(tn->idrinfo);
}
int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
struct netlink_callback *cb, int type,
const struct tc_action_ops *ops);
-int tcf_hash_search(struct tc_action_net *tn, struct tc_action **a, u32 index);
-u32 tcf_hash_new_index(struct tc_action_net *tn);
-bool tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action **a,
+int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index);
+bool tcf_idr_check(struct tc_action_net *tn, u32 index, struct tc_action **a,
int bind);
-int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
- struct tc_action **a, const struct tc_action_ops *ops, int bind,
- bool cpustats);
-void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est);
-void tcf_hash_insert(struct tc_action_net *tn, struct tc_action *a);
+int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
+ struct tc_action **a, const struct tc_action_ops *ops,
+ int bind, bool cpustats);
+void tcf_idr_cleanup(struct tc_action *a, struct nlattr *est);
+void tcf_idr_insert(struct tc_action_net *tn, struct tc_action *a);
-int __tcf_hash_release(struct tc_action *a, bool bind, bool strict);
+int __tcf_idr_release(struct tc_action *a, bool bind, bool strict);
-static inline int tcf_hash_release(struct tc_action *a, bool bind)
+static inline int tcf_idr_release(struct tc_action *a, bool bind)
{
- return __tcf_hash_release(a, bind, false);
+ return __tcf_idr_release(a, bind, false);
}
int tcf_register_action(struct tc_action_ops *a, struct pernet_operations *ops);
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 02fcb0c..7a10a90 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -70,11 +70,11 @@ static void free_tcf(struct rcu_head *head)
kfree(p);
}
-static void tcf_hash_destroy(struct tcf_hashinfo *hinfo, struct tc_action *p)
+static void tcf_idr_remove(struct tcf_idrinfo *idrinfo, struct tc_action *p)
{
- spin_lock_bh(&hinfo->lock);
- hlist_del(&p->tcfa_head);
- spin_unlock_bh(&hinfo->lock);
+ spin_lock_bh(&idrinfo->lock);
+ idr_remove(&idrinfo->action_idr, p->tcfa_index);
+ spin_unlock_bh(&idrinfo->lock);
gen_kill_estimator(&p->tcfa_rate_est);
/*
* gen_estimator est_timer() might access p->tcfa_lock
@@ -83,7 +83,7 @@ static void tcf_hash_destroy(struct tcf_hashinfo *hinfo, struct tc_action *p)
call_rcu(&p->tcfa_rcu, free_tcf);
}
-int __tcf_hash_release(struct tc_action *p, bool bind, bool strict)
+int __tcf_idr_release(struct tc_action *p, bool bind, bool strict)
{
int ret = 0;
@@ -97,64 +97,60 @@ int __tcf_hash_release(struct tc_action *p, bool bind, bool strict)
if (p->tcfa_bindcnt <= 0 && p->tcfa_refcnt <= 0) {
if (p->ops->cleanup)
p->ops->cleanup(p, bind);
- tcf_hash_destroy(p->hinfo, p);
+ tcf_idr_remove(p->idrinfo, p);
ret = ACT_P_DELETED;
}
}
return ret;
}
-EXPORT_SYMBOL(__tcf_hash_release);
+EXPORT_SYMBOL(__tcf_idr_release);
-static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
+static int tcf_dump_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
struct netlink_callback *cb)
{
- int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
+ int err = 0, index = -1, s_i = 0, n_i = 0;
u32 act_flags = cb->args[2];
unsigned long jiffy_since = cb->args[3];
struct nlattr *nest;
+ struct idr *idr = &idrinfo->action_idr;
+ struct tc_action *p;
+ unsigned long id = 1;
- spin_lock_bh(&hinfo->lock);
+ spin_lock_bh(&idrinfo->lock);
s_i = cb->args[0];
- for (i = 0; i < (hinfo->hmask + 1); i++) {
- struct hlist_head *head;
- struct tc_action *p;
-
- head = &hinfo->htab[tcf_hash(i, hinfo->hmask)];
-
- hlist_for_each_entry_rcu(p, head, tcfa_head) {
- index++;
- if (index < s_i)
- continue;
-
- if (jiffy_since &&
- time_after(jiffy_since,
- (unsigned long)p->tcfa_tm.lastuse))
- continue;
-
- nest = nla_nest_start(skb, n_i);
- if (nest == NULL)
- goto nla_put_failure;
- err = tcf_action_dump_1(skb, p, 0, 0);
- if (err < 0) {
- index--;
- nlmsg_trim(skb, nest);
- goto done;
- }
- nla_nest_end(skb, nest);
- n_i++;
- if (!(act_flags & TCA_FLAG_LARGE_DUMP_ON) &&
- n_i >= TCA_ACT_MAX_PRIO)
- goto done;
+ idr_for_each_entry(idr, p, id) {
+ index++;
+ if (index < s_i)
+ continue;
+
+ if (jiffy_since &&
+ time_after(jiffy_since,
+ (unsigned long)p->tcfa_tm.lastuse))
+ continue;
+
+ nest = nla_nest_start(skb, n_i);
+ if (!nest)
+ goto nla_put_failure;
+ err = tcf_action_dump_1(skb, p, 0, 0);
+ if (err < 0) {
+ index--;
+ nlmsg_trim(skb, nest);
+ goto done;
}
+ nla_nest_end(skb, nest);
+ n_i++;
+ if (!(act_flags & TCA_FLAG_LARGE_DUMP_ON) &&
+ n_i >= TCA_ACT_MAX_PRIO)
+ goto done;
}
done:
if (index >= 0)
cb->args[0] = index + 1;
- spin_unlock_bh(&hinfo->lock);
+ spin_unlock_bh(&idrinfo->lock);
if (n_i) {
if (act_flags & TCA_FLAG_LARGE_DUMP_ON)
cb->args[1] = n_i;
@@ -166,31 +162,29 @@ static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
goto done;
}
-static int tcf_del_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
+static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
const struct tc_action_ops *ops)
{
struct nlattr *nest;
- int i = 0, n_i = 0;
+ int n_i = 0;
int ret = -EINVAL;
+ struct idr *idr = &idrinfo->action_idr;
+ struct tc_action *p;
+ unsigned long id = 1;
nest = nla_nest_start(skb, 0);
if (nest == NULL)
goto nla_put_failure;
if (nla_put_string(skb, TCA_KIND, ops->kind))
goto nla_put_failure;
- for (i = 0; i < (hinfo->hmask + 1); i++) {
- struct hlist_head *head;
- struct hlist_node *n;
- struct tc_action *p;
-
- head = &hinfo->htab[tcf_hash(i, hinfo->hmask)];
- hlist_for_each_entry_safe(p, n, head, tcfa_head) {
- ret = __tcf_hash_release(p, false, true);
- if (ret == ACT_P_DELETED) {
- module_put(p->ops->owner);
- n_i++;
- } else if (ret < 0)
- goto nla_put_failure;
+
+ idr_for_each_entry(idr, p, id) {
+ ret = __tcf_idr_release(p, false, true);
+ if (ret == ACT_P_DELETED) {
+ module_put(p->ops->owner);
+ n_i++;
+ } else if (ret < 0) {
+ goto nla_put_failure;
}
}
if (nla_put_u32(skb, TCA_FCNT, n_i))
@@ -207,12 +201,12 @@ int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
struct netlink_callback *cb, int type,
const struct tc_action_ops *ops)
{
- struct tcf_hashinfo *hinfo = tn->hinfo;
+ struct tcf_idrinfo *idrinfo = tn->idrinfo;
if (type == RTM_DELACTION) {
- return tcf_del_walker(hinfo, skb, ops);
+ return tcf_del_walker(idrinfo, skb, ops);
} else if (type == RTM_GETACTION) {
- return tcf_dump_walker(hinfo, skb, cb);
+ return tcf_dump_walker(idrinfo, skb, cb);
} else {
WARN(1, "tcf_generic_walker: unknown action %d\n", type);
return -EINVAL;
@@ -220,40 +214,21 @@ int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
}
EXPORT_SYMBOL(tcf_generic_walker);
-static struct tc_action *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo)
+static struct tc_action *tcf_idr_lookup(u32 index, struct tcf_idrinfo *idrinfo)
{
struct tc_action *p = NULL;
- struct hlist_head *head;
- spin_lock_bh(&hinfo->lock);
- head = &hinfo->htab[tcf_hash(index, hinfo->hmask)];
- hlist_for_each_entry_rcu(p, head, tcfa_head)
- if (p->tcfa_index == index)
- break;
- spin_unlock_bh(&hinfo->lock);
+ spin_lock_bh(&idrinfo->lock);
+ p = idr_find(&idrinfo->action_idr, index);
+ spin_unlock_bh(&idrinfo->lock);
return p;
}
-u32 tcf_hash_new_index(struct tc_action_net *tn)
-{
- struct tcf_hashinfo *hinfo = tn->hinfo;
- u32 val = hinfo->index;
-
- do {
- if (++val == 0)
- val = 1;
- } while (tcf_hash_lookup(val, hinfo));
-
- hinfo->index = val;
- return val;
-}
-EXPORT_SYMBOL(tcf_hash_new_index);
-
-int tcf_hash_search(struct tc_action_net *tn, struct tc_action **a, u32 index)
+int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index)
{
- struct tcf_hashinfo *hinfo = tn->hinfo;
- struct tc_action *p = tcf_hash_lookup(index, hinfo);
+ struct tcf_idrinfo *idrinfo = tn->idrinfo;
+ struct tc_action *p = tcf_idr_lookup(index, idrinfo);
if (p) {
*a = p;
@@ -261,15 +236,15 @@ int tcf_hash_search(struct tc_action_net *tn, struct tc_action **a, u32 index)
}
return 0;
}
-EXPORT_SYMBOL(tcf_hash_search);
+EXPORT_SYMBOL(tcf_idr_search);
-bool tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action **a,
- int bind)
+bool tcf_idr_check(struct tc_action_net *tn, u32 index, struct tc_action **a,
+ int bind)
{
- struct tcf_hashinfo *hinfo = tn->hinfo;
- struct tc_action *p = NULL;
+ struct tcf_idrinfo *idrinfo = tn->idrinfo;
+ struct tc_action *p = tcf_idr_lookup(index, idrinfo);
- if (index && (p = tcf_hash_lookup(index, hinfo)) != NULL) {
+ if (index && p) {
if (bind)
p->tcfa_bindcnt++;
p->tcfa_refcnt++;
@@ -278,23 +253,25 @@ bool tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action **a,
}
return false;
}
-EXPORT_SYMBOL(tcf_hash_check);
+EXPORT_SYMBOL(tcf_idr_check);
-void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est)
+void tcf_idr_cleanup(struct tc_action *a, struct nlattr *est)
{
if (est)
gen_kill_estimator(&a->tcfa_rate_est);
call_rcu(&a->tcfa_rcu, free_tcf);
}
-EXPORT_SYMBOL(tcf_hash_cleanup);
+EXPORT_SYMBOL(tcf_idr_cleanup);
-int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
- struct tc_action **a, const struct tc_action_ops *ops,
- int bind, bool cpustats)
+int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
+ struct tc_action **a, const struct tc_action_ops *ops,
+ int bind, bool cpustats)
{
struct tc_action *p = kzalloc(ops->size, GFP_KERNEL);
- struct tcf_hashinfo *hinfo = tn->hinfo;
+ struct tcf_idrinfo *idrinfo = tn->idrinfo;
+ struct idr *idr = &idrinfo->action_idr;
int err = -ENOMEM;
+ unsigned long idr_index;
if (unlikely(!p))
return -ENOMEM;
@@ -317,8 +294,26 @@ int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
}
}
spin_lock_init(&p->tcfa_lock);
- INIT_HLIST_NODE(&p->tcfa_head);
- p->tcfa_index = index ? index : tcf_hash_new_index(tn);
+ /* user doesn't specify an index */
+ if (!index) {
+ spin_lock_bh(&idrinfo->lock);
+ err = idr_alloc(idr, NULL, &idr_index, 1, 0, GFP_KERNEL);
+ spin_unlock_bh(&idrinfo->lock);
+ if (err) {
+err3:
+ free_percpu(p->cpu_qstats);
+ goto err2;
+ }
+ p->tcfa_index = idr_index;
+ } else {
+ spin_lock_bh(&idrinfo->lock);
+ err = idr_alloc(idr, NULL, NULL, index, index + 1, GFP_KERNEL);
+ spin_unlock_bh(&idrinfo->lock);
+ if (err)
+ goto err3;
+ p->tcfa_index = index;
+ }
+
p->tcfa_tm.install = jiffies;
p->tcfa_tm.lastuse = jiffies;
p->tcfa_tm.firstuse = 0;
@@ -327,52 +322,46 @@ int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
&p->tcfa_rate_est,
&p->tcfa_lock, NULL, est);
if (err) {
- free_percpu(p->cpu_qstats);
- goto err2;
+ goto err3;
}
}
- p->hinfo = hinfo;
+ p->idrinfo = idrinfo;
p->ops = ops;
INIT_LIST_HEAD(&p->list);
*a = p;
return 0;
}
-EXPORT_SYMBOL(tcf_hash_create);
+EXPORT_SYMBOL(tcf_idr_create);
-void tcf_hash_insert(struct tc_action_net *tn, struct tc_action *a)
+void tcf_idr_insert(struct tc_action_net *tn, struct tc_action *a)
{
- struct tcf_hashinfo *hinfo = tn->hinfo;
- unsigned int h = tcf_hash(a->tcfa_index, hinfo->hmask);
+ struct tcf_idrinfo *idrinfo = tn->idrinfo;
- spin_lock_bh(&hinfo->lock);
- hlist_add_head(&a->tcfa_head, &hinfo->htab[h]);
- spin_unlock_bh(&hinfo->lock);
+ spin_lock_bh(&idrinfo->lock);
+ idr_replace(&idrinfo->action_idr, a, a->tcfa_index);
+ spin_unlock_bh(&idrinfo->lock);
}
-EXPORT_SYMBOL(tcf_hash_insert);
+EXPORT_SYMBOL(tcf_idr_insert);
-void tcf_hashinfo_destroy(const struct tc_action_ops *ops,
- struct tcf_hashinfo *hinfo)
+void tcf_idrinfo_destroy(const struct tc_action_ops *ops,
+ struct tcf_idrinfo *idrinfo)
{
- int i;
-
- for (i = 0; i < hinfo->hmask + 1; i++) {
- struct tc_action *p;
- struct hlist_node *n;
-
- hlist_for_each_entry_safe(p, n, &hinfo->htab[i], tcfa_head) {
- int ret;
+ struct idr *idr = &idrinfo->action_idr;
+ struct tc_action *p;
+ int ret;
+ unsigned long id = 1;
- ret = __tcf_hash_release(p, false, true);
- if (ret == ACT_P_DELETED)
- module_put(ops->owner);
- else if (ret < 0)
- return;
- }
+ idr_for_each_entry(idr, p, id) {
+ ret = __tcf_idr_release(p, false, true);
+ if (ret == ACT_P_DELETED)
+ module_put(ops->owner);
+ else if (ret < 0)
+ return;
}
- kfree(hinfo->htab);
+ idr_destroy(&idrinfo->action_idr);
}
-EXPORT_SYMBOL(tcf_hashinfo_destroy);
+EXPORT_SYMBOL(tcf_idrinfo_destroy);
static LIST_HEAD(act_base);
static DEFINE_RWLOCK(act_mod_lock);
@@ -524,7 +513,7 @@ int tcf_action_destroy(struct list_head *actions, int bind)
int ret = 0;
list_for_each_entry_safe(a, tmp, actions, list) {
- ret = __tcf_hash_release(a, bind, true);
+ ret = __tcf_idr_release(a, bind, true);
if (ret == ACT_P_DELETED)
module_put(a->ops->owner);
else if (ret < 0)
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
index 9afe133..c0c707e 100644
--- a/net/sched/act_bpf.c
+++ b/net/sched/act_bpf.c
@@ -21,7 +21,6 @@
#include <linux/tc_act/tc_bpf.h>
#include <net/tc_act/tc_bpf.h>
-#define BPF_TAB_MASK 15
#define ACT_BPF_NAME_LEN 256
struct tcf_bpf_cfg {
@@ -295,9 +294,9 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
parm = nla_data(tb[TCA_ACT_BPF_PARMS]);
- if (!tcf_hash_check(tn, parm->index, act, bind)) {
- ret = tcf_hash_create(tn, parm->index, est, act,
- &act_bpf_ops, bind, true);
+ if (!tcf_idr_check(tn, parm->index, act, bind)) {
+ ret = tcf_idr_create(tn, parm->index, est, act,
+ &act_bpf_ops, bind, true);
if (ret < 0)
return ret;
@@ -307,7 +306,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
if (bind)
return 0;
- tcf_hash_release(*act, bind);
+ tcf_idr_release(*act, bind);
if (!replace)
return -EEXIST;
}
@@ -343,7 +342,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
rcu_assign_pointer(prog->filter, cfg.filter);
if (res == ACT_P_CREATED) {
- tcf_hash_insert(tn, *act);
+ tcf_idr_insert(tn, *act);
} else {
/* make sure the program being replaced is no longer executing */
synchronize_rcu();
@@ -353,7 +352,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
return res;
out:
if (res == ACT_P_CREATED)
- tcf_hash_cleanup(*act, est);
+ tcf_idr_cleanup(*act, est);
return ret;
}
@@ -379,7 +378,7 @@ static int tcf_bpf_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, bpf_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static struct tc_action_ops act_bpf_ops __read_mostly = {
@@ -399,7 +398,7 @@ static __net_init int bpf_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, bpf_net_id);
- return tc_action_net_init(tn, &act_bpf_ops, BPF_TAB_MASK);
+ return tc_action_net_init(tn, &act_bpf_ops);
}
static void __net_exit bpf_exit_net(struct net *net)
diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c
index 2155bc6..10b7a88 100644
--- a/net/sched/act_connmark.c
+++ b/net/sched/act_connmark.c
@@ -28,8 +28,6 @@
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_zones.h>
-#define CONNMARK_TAB_MASK 3
-
static unsigned int connmark_net_id;
static struct tc_action_ops act_connmark_ops;
@@ -119,9 +117,9 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
parm = nla_data(tb[TCA_CONNMARK_PARMS]);
- if (!tcf_hash_check(tn, parm->index, a, bind)) {
- ret = tcf_hash_create(tn, parm->index, est, a,
- &act_connmark_ops, bind, false);
+ if (!tcf_idr_check(tn, parm->index, a, bind)) {
+ ret = tcf_idr_create(tn, parm->index, est, a,
+ &act_connmark_ops, bind, false);
if (ret)
return ret;
@@ -130,13 +128,13 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
ci->net = net;
ci->zone = parm->zone;
- tcf_hash_insert(tn, *a);
+ tcf_idr_insert(tn, *a);
ret = ACT_P_CREATED;
} else {
ci = to_connmark(*a);
if (bind)
return 0;
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (!ovr)
return -EEXIST;
/* replacing action and zone */
@@ -189,7 +187,7 @@ static int tcf_connmark_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, connmark_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static struct tc_action_ops act_connmark_ops = {
@@ -208,7 +206,7 @@ static __net_init int connmark_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, connmark_net_id);
- return tc_action_net_init(tn, &act_connmark_ops, CONNMARK_TAB_MASK);
+ return tc_action_net_init(tn, &act_connmark_ops);
}
static void __net_exit connmark_exit_net(struct net *net)
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
index 67afc12..1c40caa 100644
--- a/net/sched/act_csum.c
+++ b/net/sched/act_csum.c
@@ -37,8 +37,6 @@
#include <linux/tc_act/tc_csum.h>
#include <net/tc_act/tc_csum.h>
-#define CSUM_TAB_MASK 15
-
static const struct nla_policy csum_policy[TCA_CSUM_MAX + 1] = {
[TCA_CSUM_PARMS] = { .len = sizeof(struct tc_csum), },
};
@@ -67,16 +65,16 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
return -EINVAL;
parm = nla_data(tb[TCA_CSUM_PARMS]);
- if (!tcf_hash_check(tn, parm->index, a, bind)) {
- ret = tcf_hash_create(tn, parm->index, est, a,
- &act_csum_ops, bind, false);
+ if (!tcf_idr_check(tn, parm->index, a, bind)) {
+ ret = tcf_idr_create(tn, parm->index, est, a,
+ &act_csum_ops, bind, false);
if (ret)
return ret;
ret = ACT_P_CREATED;
} else {
if (bind)/* dont override defaults */
return 0;
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (!ovr)
return -EEXIST;
}
@@ -88,7 +86,7 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
spin_unlock_bh(&p->tcf_lock);
if (ret == ACT_P_CREATED)
- tcf_hash_insert(tn, *a);
+ tcf_idr_insert(tn, *a);
return ret;
}
@@ -609,7 +607,7 @@ static int tcf_csum_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, csum_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static struct tc_action_ops act_csum_ops = {
@@ -628,7 +626,7 @@ static __net_init int csum_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, csum_net_id);
- return tc_action_net_init(tn, &act_csum_ops, CSUM_TAB_MASK);
+ return tc_action_net_init(tn, &act_csum_ops);
}
static void __net_exit csum_exit_net(struct net *net)
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
index 99afe8b..e29a48e 100644
--- a/net/sched/act_gact.c
+++ b/net/sched/act_gact.c
@@ -23,8 +23,6 @@
#include <linux/tc_act/tc_gact.h>
#include <net/tc_act/tc_gact.h>
-#define GACT_TAB_MASK 15
-
static unsigned int gact_net_id;
static struct tc_action_ops act_gact_ops;
@@ -92,16 +90,16 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
}
#endif
- if (!tcf_hash_check(tn, parm->index, a, bind)) {
- ret = tcf_hash_create(tn, parm->index, est, a,
- &act_gact_ops, bind, true);
+ if (!tcf_idr_check(tn, parm->index, a, bind)) {
+ ret = tcf_idr_create(tn, parm->index, est, a,
+ &act_gact_ops, bind, true);
if (ret)
return ret;
ret = ACT_P_CREATED;
} else {
if (bind)/* dont override defaults */
return 0;
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (!ovr)
return -EEXIST;
}
@@ -122,7 +120,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
}
#endif
if (ret == ACT_P_CREATED)
- tcf_hash_insert(tn, *a);
+ tcf_idr_insert(tn, *a);
return ret;
}
@@ -214,7 +212,7 @@ static int tcf_gact_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, gact_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static struct tc_action_ops act_gact_ops = {
@@ -234,7 +232,7 @@ static __net_init int gact_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, gact_net_id);
- return tc_action_net_init(tn, &act_gact_ops, GACT_TAB_MASK);
+ return tc_action_net_init(tn, &act_gact_ops);
}
static void __net_exit gact_exit_net(struct net *net)
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index c5dec30..770c5d9 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c
@@ -34,8 +34,6 @@
#include <linux/etherdevice.h>
#include <net/ife.h>
-#define IFE_TAB_MASK 15
-
static unsigned int ife_net_id;
static int max_metacnt = IFE_META_MAX + 1;
static struct tc_action_ops act_ife_ops;
@@ -452,7 +450,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
parm = nla_data(tb[TCA_IFE_PARMS]);
- exists = tcf_hash_check(tn, parm->index, a, bind);
+ exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind)
return 0;
@@ -462,20 +460,20 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
**/
if (!tb[TCA_IFE_TYPE]) {
if (exists)
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
pr_info("You MUST pass etherype for encoding\n");
return -EINVAL;
}
}
if (!exists) {
- ret = tcf_hash_create(tn, parm->index, est, a, &act_ife_ops,
- bind, false);
+ ret = tcf_idr_create(tn, parm->index, est, a, &act_ife_ops,
+ bind, false);
if (ret)
return ret;
ret = ACT_P_CREATED;
} else {
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (!ovr)
return -EEXIST;
}
@@ -518,7 +516,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
if (err) {
metadata_parse_err:
if (exists)
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (ret == ACT_P_CREATED)
_tcf_ife_cleanup(*a, bind);
@@ -552,7 +550,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
spin_unlock_bh(&ife->tcf_lock);
if (ret == ACT_P_CREATED)
- tcf_hash_insert(tn, *a);
+ tcf_idr_insert(tn, *a);
return ret;
}
@@ -811,7 +809,7 @@ static int tcf_ife_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, ife_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static struct tc_action_ops act_ife_ops = {
@@ -831,7 +829,7 @@ static __net_init int ife_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, ife_net_id);
- return tc_action_net_init(tn, &act_ife_ops, IFE_TAB_MASK);
+ return tc_action_net_init(tn, &act_ife_ops);
}
static void __net_exit ife_exit_net(struct net *net)
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index d516ba8..c59f600 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -28,8 +28,6 @@
#include <linux/netfilter_ipv4/ip_tables.h>
-#define IPT_TAB_MASK 15
-
static unsigned int ipt_net_id;
static struct tc_action_ops act_ipt_ops;
@@ -116,33 +114,33 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla,
if (tb[TCA_IPT_INDEX] != NULL)
index = nla_get_u32(tb[TCA_IPT_INDEX]);
- exists = tcf_hash_check(tn, index, a, bind);
+ exists = tcf_idr_check(tn, index, a, bind);
if (exists && bind)
return 0;
if (tb[TCA_IPT_HOOK] == NULL || tb[TCA_IPT_TARG] == NULL) {
if (exists)
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
return -EINVAL;
}
td = (struct xt_entry_target *)nla_data(tb[TCA_IPT_TARG]);
if (nla_len(tb[TCA_IPT_TARG]) < td->u.target_size) {
if (exists)
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
return -EINVAL;
}
if (!exists) {
- ret = tcf_hash_create(tn, index, est, a, ops, bind,
- false);
+ ret = tcf_idr_create(tn, index, est, a, ops, bind,
+ false);
if (ret)
return ret;
ret = ACT_P_CREATED;
} else {
if (bind)/* dont override defaults */
return 0;
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (!ovr)
return -EEXIST;
@@ -178,7 +176,7 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla,
ipt->tcfi_hook = hook;
spin_unlock_bh(&ipt->tcf_lock);
if (ret == ACT_P_CREATED)
- tcf_hash_insert(tn, *a);
+ tcf_idr_insert(tn, *a);
return ret;
err3:
@@ -187,7 +185,7 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla,
kfree(tname);
err1:
if (ret == ACT_P_CREATED)
- tcf_hash_cleanup(*a, est);
+ tcf_idr_cleanup(*a, est);
return err;
}
@@ -314,7 +312,7 @@ static int tcf_ipt_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, ipt_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static struct tc_action_ops act_ipt_ops = {
@@ -334,7 +332,7 @@ static __net_init int ipt_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, ipt_net_id);
- return tc_action_net_init(tn, &act_ipt_ops, IPT_TAB_MASK);
+ return tc_action_net_init(tn, &act_ipt_ops);
}
static void __net_exit ipt_exit_net(struct net *net)
@@ -364,7 +362,7 @@ static int tcf_xt_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, xt_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static struct tc_action_ops act_xt_ops = {
@@ -384,7 +382,7 @@ static __net_init int xt_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, xt_net_id);
- return tc_action_net_init(tn, &act_xt_ops, IPT_TAB_MASK);
+ return tc_action_net_init(tn, &act_xt_ops);
}
static void __net_exit xt_exit_net(struct net *net)
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 1b5549a..416627c 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -28,7 +28,6 @@
#include <linux/tc_act/tc_mirred.h>
#include <net/tc_act/tc_mirred.h>
-#define MIRRED_TAB_MASK 7
static LIST_HEAD(mirred_list);
static DEFINE_SPINLOCK(mirred_list_lock);
@@ -94,7 +93,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
return -EINVAL;
parm = nla_data(tb[TCA_MIRRED_PARMS]);
- exists = tcf_hash_check(tn, parm->index, a, bind);
+ exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind)
return 0;
@@ -106,14 +105,14 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
break;
default:
if (exists)
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
return -EINVAL;
}
if (parm->ifindex) {
dev = __dev_get_by_index(net, parm->ifindex);
if (dev == NULL) {
if (exists)
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
return -ENODEV;
}
mac_header_xmit = dev_is_mac_header_xmit(dev);
@@ -124,13 +123,13 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
if (!exists) {
if (dev == NULL)
return -EINVAL;
- ret = tcf_hash_create(tn, parm->index, est, a,
- &act_mirred_ops, bind, true);
+ ret = tcf_idr_create(tn, parm->index, est, a,
+ &act_mirred_ops, bind, true);
if (ret)
return ret;
ret = ACT_P_CREATED;
} else {
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (!ovr)
return -EEXIST;
}
@@ -152,7 +151,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
spin_lock_bh(&mirred_list_lock);
list_add(&m->tcfm_list, &mirred_list);
spin_unlock_bh(&mirred_list_lock);
- tcf_hash_insert(tn, *a);
+ tcf_idr_insert(tn, *a);
}
return ret;
@@ -283,7 +282,7 @@ static int tcf_mirred_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, mirred_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static int mirred_device_event(struct notifier_block *unused,
@@ -344,7 +343,7 @@ static __net_init int mirred_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, mirred_net_id);
- return tc_action_net_init(tn, &act_mirred_ops, MIRRED_TAB_MASK);
+ return tc_action_net_init(tn, &act_mirred_ops);
}
static void __net_exit mirred_exit_net(struct net *net)
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
index 9016ab8..c365d01 100644
--- a/net/sched/act_nat.c
+++ b/net/sched/act_nat.c
@@ -29,8 +29,6 @@
#include <net/udp.h>
-#define NAT_TAB_MASK 15
-
static unsigned int nat_net_id;
static struct tc_action_ops act_nat_ops;
@@ -58,16 +56,16 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
return -EINVAL;
parm = nla_data(tb[TCA_NAT_PARMS]);
- if (!tcf_hash_check(tn, parm->index, a, bind)) {
- ret = tcf_hash_create(tn, parm->index, est, a,
- &act_nat_ops, bind, false);
+ if (!tcf_idr_check(tn, parm->index, a, bind)) {
+ ret = tcf_idr_create(tn, parm->index, est, a,
+ &act_nat_ops, bind, false);
if (ret)
return ret;
ret = ACT_P_CREATED;
} else {
if (bind)
return 0;
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (!ovr)
return -EEXIST;
}
@@ -83,7 +81,7 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
spin_unlock_bh(&p->tcf_lock);
if (ret == ACT_P_CREATED)
- tcf_hash_insert(tn, *a);
+ tcf_idr_insert(tn, *a);
return ret;
}
@@ -290,7 +288,7 @@ static int tcf_nat_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, nat_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static struct tc_action_ops act_nat_ops = {
@@ -309,7 +307,7 @@ static __net_init int nat_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, nat_net_id);
- return tc_action_net_init(tn, &act_nat_ops, NAT_TAB_MASK);
+ return tc_action_net_init(tn, &act_nat_ops);
}
static void __net_exit nat_exit_net(struct net *net)
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index 7dc5892..491fe5de 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -24,8 +24,6 @@
#include <net/tc_act/tc_pedit.h>
#include <uapi/linux/tc_act/tc_pedit.h>
-#define PEDIT_TAB_MASK 15
-
static unsigned int pedit_net_id;
static struct tc_action_ops act_pedit_ops;
@@ -168,17 +166,17 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
if (IS_ERR(keys_ex))
return PTR_ERR(keys_ex);
- if (!tcf_hash_check(tn, parm->index, a, bind)) {
+ if (!tcf_idr_check(tn, parm->index, a, bind)) {
if (!parm->nkeys)
return -EINVAL;
- ret = tcf_hash_create(tn, parm->index, est, a,
- &act_pedit_ops, bind, false);
+ ret = tcf_idr_create(tn, parm->index, est, a,
+ &act_pedit_ops, bind, false);
if (ret)
return ret;
p = to_pedit(*a);
keys = kmalloc(ksize, GFP_KERNEL);
if (keys == NULL) {
- tcf_hash_cleanup(*a, est);
+ tcf_idr_cleanup(*a, est);
kfree(keys_ex);
return -ENOMEM;
}
@@ -186,7 +184,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
} else {
if (bind)
return 0;
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (!ovr)
return -EEXIST;
p = to_pedit(*a);
@@ -214,7 +212,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
spin_unlock_bh(&p->tcf_lock);
if (ret == ACT_P_CREATED)
- tcf_hash_insert(tn, *a);
+ tcf_idr_insert(tn, *a);
return ret;
}
@@ -432,7 +430,7 @@ static int tcf_pedit_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, pedit_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static struct tc_action_ops act_pedit_ops = {
@@ -452,7 +450,7 @@ static __net_init int pedit_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, pedit_net_id);
- return tc_action_net_init(tn, &act_pedit_ops, PEDIT_TAB_MASK);
+ return tc_action_net_init(tn, &act_pedit_ops);
}
static void __net_exit pedit_exit_net(struct net *net)
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index b062bc8..3bb2ebf 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -40,8 +40,6 @@ struct tcf_police {
#define to_police(pc) ((struct tcf_police *)pc)
-#define POL_TAB_MASK 15
-
/* old policer structure from before tc actions */
struct tc_police_compat {
u32 index;
@@ -101,18 +99,18 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla,
return -EINVAL;
parm = nla_data(tb[TCA_POLICE_TBF]);
- exists = tcf_hash_check(tn, parm->index, a, bind);
+ exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind)
return 0;
if (!exists) {
- ret = tcf_hash_create(tn, parm->index, NULL, a,
- &act_police_ops, bind, false);
+ ret = tcf_idr_create(tn, parm->index, NULL, a,
+ &act_police_ops, bind, false);
if (ret)
return ret;
ret = ACT_P_CREATED;
} else {
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (!ovr)
return -EEXIST;
}
@@ -188,7 +186,7 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla,
return ret;
police->tcfp_t_c = ktime_get_ns();
- tcf_hash_insert(tn, *a);
+ tcf_idr_insert(tn, *a);
return ret;
@@ -196,7 +194,7 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla,
qdisc_put_rtab(P_tab);
qdisc_put_rtab(R_tab);
if (ret == ACT_P_CREATED)
- tcf_hash_cleanup(*a, est);
+ tcf_idr_cleanup(*a, est);
return err;
}
@@ -310,7 +308,7 @@ static int tcf_police_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, police_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
MODULE_AUTHOR("Alexey Kuznetsov");
@@ -333,7 +331,7 @@ static __net_init int police_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, police_net_id);
- return tc_action_net_init(tn, &act_police_ops, POL_TAB_MASK);
+ return tc_action_net_init(tn, &act_police_ops);
}
static void __net_exit police_exit_net(struct net *net)
diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c
index 59d6645..ec986ae 100644
--- a/net/sched/act_sample.c
+++ b/net/sched/act_sample.c
@@ -25,7 +25,6 @@
#include <linux/if_arp.h>
-#define SAMPLE_TAB_MASK 7
static unsigned int sample_net_id;
static struct tc_action_ops act_sample_ops;
@@ -59,18 +58,18 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
parm = nla_data(tb[TCA_SAMPLE_PARMS]);
- exists = tcf_hash_check(tn, parm->index, a, bind);
+ exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind)
return 0;
if (!exists) {
- ret = tcf_hash_create(tn, parm->index, est, a,
- &act_sample_ops, bind, false);
+ ret = tcf_idr_create(tn, parm->index, est, a,
+ &act_sample_ops, bind, false);
if (ret)
return ret;
ret = ACT_P_CREATED;
} else {
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (!ovr)
return -EEXIST;
}
@@ -82,7 +81,7 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
psample_group = psample_group_get(net, s->psample_group_num);
if (!psample_group) {
if (ret == ACT_P_CREATED)
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
return -ENOMEM;
}
RCU_INIT_POINTER(s->psample_group, psample_group);
@@ -93,7 +92,7 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
}
if (ret == ACT_P_CREATED)
- tcf_hash_insert(tn, *a);
+ tcf_idr_insert(tn, *a);
return ret;
}
@@ -221,7 +220,7 @@ static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, sample_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static struct tc_action_ops act_sample_ops = {
@@ -241,7 +240,7 @@ static __net_init int sample_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, sample_net_id);
- return tc_action_net_init(tn, &act_sample_ops, SAMPLE_TAB_MASK);
+ return tc_action_net_init(tn, &act_sample_ops);
}
static void __net_exit sample_exit_net(struct net *net)
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
index 43605e7..e7b57e5 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -24,8 +24,6 @@
#include <linux/tc_act/tc_defact.h>
#include <net/tc_act/tc_defact.h>
-#define SIMP_TAB_MASK 7
-
static unsigned int simp_net_id;
static struct tc_action_ops act_simp_ops;
@@ -102,28 +100,28 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
return -EINVAL;
parm = nla_data(tb[TCA_DEF_PARMS]);
- exists = tcf_hash_check(tn, parm->index, a, bind);
+ exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind)
return 0;
if (tb[TCA_DEF_DATA] == NULL) {
if (exists)
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
return -EINVAL;
}
defdata = nla_data(tb[TCA_DEF_DATA]);
if (!exists) {
- ret = tcf_hash_create(tn, parm->index, est, a,
- &act_simp_ops, bind, false);
+ ret = tcf_idr_create(tn, parm->index, est, a,
+ &act_simp_ops, bind, false);
if (ret)
return ret;
d = to_defact(*a);
ret = alloc_defdata(d, defdata);
if (ret < 0) {
- tcf_hash_cleanup(*a, est);
+ tcf_idr_cleanup(*a, est);
return ret;
}
d->tcf_action = parm->action;
@@ -131,7 +129,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
} else {
d = to_defact(*a);
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (!ovr)
return -EEXIST;
@@ -139,7 +137,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
}
if (ret == ACT_P_CREATED)
- tcf_hash_insert(tn, *a);
+ tcf_idr_insert(tn, *a);
return ret;
}
@@ -183,7 +181,7 @@ static int tcf_simp_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, simp_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static struct tc_action_ops act_simp_ops = {
@@ -203,7 +201,7 @@ static __net_init int simp_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, simp_net_id);
- return tc_action_net_init(tn, &act_simp_ops, SIMP_TAB_MASK);
+ return tc_action_net_init(tn, &act_simp_ops);
}
static void __net_exit simp_exit_net(struct net *net)
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index 6b3e65d..59949d6 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c
@@ -27,8 +27,6 @@
#include <linux/tc_act/tc_skbedit.h>
#include <net/tc_act/tc_skbedit.h>
-#define SKBEDIT_TAB_MASK 15
-
static unsigned int skbedit_net_id;
static struct tc_action_ops act_skbedit_ops;
@@ -118,18 +116,18 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
- exists = tcf_hash_check(tn, parm->index, a, bind);
+ exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind)
return 0;
if (!flags) {
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
return -EINVAL;
}
if (!exists) {
- ret = tcf_hash_create(tn, parm->index, est, a,
- &act_skbedit_ops, bind, false);
+ ret = tcf_idr_create(tn, parm->index, est, a,
+ &act_skbedit_ops, bind, false);
if (ret)
return ret;
@@ -137,7 +135,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
ret = ACT_P_CREATED;
} else {
d = to_skbedit(*a);
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (!ovr)
return -EEXIST;
}
@@ -163,7 +161,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
spin_unlock_bh(&d->tcf_lock);
if (ret == ACT_P_CREATED)
- tcf_hash_insert(tn, *a);
+ tcf_idr_insert(tn, *a);
return ret;
}
@@ -221,7 +219,7 @@ static int tcf_skbedit_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, skbedit_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static struct tc_action_ops act_skbedit_ops = {
@@ -240,7 +238,7 @@ static __net_init int skbedit_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, skbedit_net_id);
- return tc_action_net_init(tn, &act_skbedit_ops, SKBEDIT_TAB_MASK);
+ return tc_action_net_init(tn, &act_skbedit_ops);
}
static void __net_exit skbedit_exit_net(struct net *net)
diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c
index a73c4bb..b642ad3 100644
--- a/net/sched/act_skbmod.c
+++ b/net/sched/act_skbmod.c
@@ -20,8 +20,6 @@
#include <linux/tc_act/tc_skbmod.h>
#include <net/tc_act/tc_skbmod.h>
-#define SKBMOD_TAB_MASK 15
-
static unsigned int skbmod_net_id;
static struct tc_action_ops act_skbmod_ops;
@@ -129,7 +127,7 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
if (parm->flags & SKBMOD_F_SWAPMAC)
lflags = SKBMOD_F_SWAPMAC;
- exists = tcf_hash_check(tn, parm->index, a, bind);
+ exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind)
return 0;
@@ -137,14 +135,14 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
return -EINVAL;
if (!exists) {
- ret = tcf_hash_create(tn, parm->index, est, a,
- &act_skbmod_ops, bind, true);
+ ret = tcf_idr_create(tn, parm->index, est, a,
+ &act_skbmod_ops, bind, true);
if (ret)
return ret;
ret = ACT_P_CREATED;
} else {
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (!ovr)
return -EEXIST;
}
@@ -155,7 +153,7 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
p = kzalloc(sizeof(struct tcf_skbmod_params), GFP_KERNEL);
if (unlikely(!p)) {
if (ovr)
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
return -ENOMEM;
}
@@ -182,7 +180,7 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
kfree_rcu(p_old, rcu);
if (ret == ACT_P_CREATED)
- tcf_hash_insert(tn, *a);
+ tcf_idr_insert(tn, *a);
return ret;
}
@@ -245,7 +243,7 @@ static int tcf_skbmod_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, skbmod_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static struct tc_action_ops act_skbmod_ops = {
@@ -265,7 +263,7 @@ static __net_init int skbmod_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, skbmod_net_id);
- return tc_action_net_init(tn, &act_skbmod_ops, SKBMOD_TAB_MASK);
+ return tc_action_net_init(tn, &act_skbmod_ops);
}
static void __net_exit skbmod_exit_net(struct net *net)
diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c
index fd7e756..30c9627 100644
--- a/net/sched/act_tunnel_key.c
+++ b/net/sched/act_tunnel_key.c
@@ -20,8 +20,6 @@
#include <linux/tc_act/tc_tunnel_key.h>
#include <net/tc_act/tc_tunnel_key.h>
-#define TUNNEL_KEY_TAB_MASK 15
-
static unsigned int tunnel_key_net_id;
static struct tc_action_ops act_tunnel_key_ops;
@@ -100,7 +98,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
return -EINVAL;
parm = nla_data(tb[TCA_TUNNEL_KEY_PARMS]);
- exists = tcf_hash_check(tn, parm->index, a, bind);
+ exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind)
return 0;
@@ -159,14 +157,14 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
}
if (!exists) {
- ret = tcf_hash_create(tn, parm->index, est, a,
- &act_tunnel_key_ops, bind, true);
+ ret = tcf_idr_create(tn, parm->index, est, a,
+ &act_tunnel_key_ops, bind, true);
if (ret)
return ret;
ret = ACT_P_CREATED;
} else {
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (!ovr)
return -EEXIST;
}
@@ -177,7 +175,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
params_new = kzalloc(sizeof(*params_new), GFP_KERNEL);
if (unlikely(!params_new)) {
if (ret == ACT_P_CREATED)
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
return -ENOMEM;
}
@@ -193,13 +191,13 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
kfree_rcu(params_old, rcu);
if (ret == ACT_P_CREATED)
- tcf_hash_insert(tn, *a);
+ tcf_idr_insert(tn, *a);
return ret;
err_out:
if (exists)
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
return ret;
}
@@ -304,7 +302,7 @@ static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static struct tc_action_ops act_tunnel_key_ops = {
@@ -324,7 +322,7 @@ static __net_init int tunnel_key_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
- return tc_action_net_init(tn, &act_tunnel_key_ops, TUNNEL_KEY_TAB_MASK);
+ return tc_action_net_init(tn, &act_tunnel_key_ops);
}
static void __net_exit tunnel_key_exit_net(struct net *net)
diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
index 13ba3a8..16eb067 100644
--- a/net/sched/act_vlan.c
+++ b/net/sched/act_vlan.c
@@ -19,8 +19,6 @@
#include <linux/tc_act/tc_vlan.h>
#include <net/tc_act/tc_vlan.h>
-#define VLAN_TAB_MASK 15
-
static unsigned int vlan_net_id;
static struct tc_action_ops act_vlan_ops;
@@ -128,7 +126,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
if (!tb[TCA_VLAN_PARMS])
return -EINVAL;
parm = nla_data(tb[TCA_VLAN_PARMS]);
- exists = tcf_hash_check(tn, parm->index, a, bind);
+ exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind)
return 0;
@@ -139,13 +137,13 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
case TCA_VLAN_ACT_MODIFY:
if (!tb[TCA_VLAN_PUSH_VLAN_ID]) {
if (exists)
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
return -EINVAL;
}
push_vid = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_ID]);
if (push_vid >= VLAN_VID_MASK) {
if (exists)
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
return -ERANGE;
}
@@ -167,20 +165,20 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
break;
default:
if (exists)
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
return -EINVAL;
}
action = parm->v_action;
if (!exists) {
- ret = tcf_hash_create(tn, parm->index, est, a,
- &act_vlan_ops, bind, false);
+ ret = tcf_idr_create(tn, parm->index, est, a,
+ &act_vlan_ops, bind, false);
if (ret)
return ret;
ret = ACT_P_CREATED;
} else {
- tcf_hash_release(*a, bind);
+ tcf_idr_release(*a, bind);
if (!ovr)
return -EEXIST;
}
@@ -199,7 +197,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
spin_unlock_bh(&v->tcf_lock);
if (ret == ACT_P_CREATED)
- tcf_hash_insert(tn, *a);
+ tcf_idr_insert(tn, *a);
return ret;
}
@@ -252,7 +250,7 @@ static int tcf_vlan_search(struct net *net, struct tc_action **a, u32 index)
{
struct tc_action_net *tn = net_generic(net, vlan_net_id);
- return tcf_hash_search(tn, a, index);
+ return tcf_idr_search(tn, a, index);
}
static struct tc_action_ops act_vlan_ops = {
@@ -271,7 +269,7 @@ static __net_init int vlan_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, vlan_net_id);
- return tc_action_net_init(tn, &act_vlan_ops, VLAN_TAB_MASK);
+ return tc_action_net_init(tn, &act_vlan_ops);
}
static void __net_exit vlan_exit_net(struct net *net)
--
1.8.3.1
^ permalink raw reply related
* [patch net-next repost 1/3] idr: Use unsigned long instead of int
From: Chris Mi @ 2017-08-16 8:14 UTC (permalink / raw)
To: netdev; +Cc: jhs, xiyou.wangcong, jiri, davem, mawilcox
In-Reply-To: <1502871244-19870-1-git-send-email-chrism@mellanox.com>
IDR uses internally radix tree which uses unsigned long. It doesn't
makes sense to have index as signed value.
Signed-off-by: Chris Mi <chrism@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
block/bsg.c | 8 ++--
block/genhd.c | 12 +++---
drivers/atm/nicstar.c | 11 ++---
drivers/block/drbd/drbd_main.c | 31 ++++++++------
drivers/block/drbd/drbd_nl.c | 22 +++++-----
drivers/block/drbd/drbd_proc.c | 3 +-
drivers/block/drbd/drbd_receiver.c | 15 ++++---
drivers/block/drbd/drbd_state.c | 34 ++++++++-------
drivers/block/drbd/drbd_worker.c | 6 +--
drivers/block/loop.c | 17 +++++---
drivers/block/nbd.c | 20 +++++----
drivers/block/zram/zram_drv.c | 9 ++--
drivers/char/tpm/tpm-chip.c | 10 +++--
drivers/char/tpm/tpm.h | 2 +-
drivers/dca/dca-sysfs.c | 9 ++--
drivers/firewire/core-cdev.c | 18 ++++----
drivers/firewire/core-device.c | 15 ++++---
drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 8 ++--
drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 9 ++--
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 6 +--
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 2 +-
drivers/gpu/drm/drm_auth.c | 9 ++--
drivers/gpu/drm/drm_connector.c | 10 +++--
drivers/gpu/drm/drm_context.c | 20 +++++----
drivers/gpu/drm/drm_dp_aux_dev.c | 11 ++---
drivers/gpu/drm/drm_drv.c | 6 ++-
drivers/gpu/drm/drm_gem.c | 19 +++++----
drivers/gpu/drm/drm_info.c | 2 +-
drivers/gpu/drm/drm_mode_object.c | 11 +++--
drivers/gpu/drm/drm_syncobj.c | 18 +++++---
drivers/gpu/drm/exynos/exynos_drm_ipp.c | 25 ++++++-----
drivers/gpu/drm/i915/gvt/display.c | 2 +-
drivers/gpu/drm/i915/gvt/kvmgt.c | 2 +-
drivers/gpu/drm/i915/gvt/vgpu.c | 9 ++--
drivers/gpu/drm/i915/i915_debugfs.c | 6 +--
drivers/gpu/drm/i915/i915_gem_context.c | 9 ++--
drivers/gpu/drm/qxl/qxl_cmd.c | 8 ++--
drivers/gpu/drm/qxl/qxl_release.c | 14 +++---
drivers/gpu/drm/sis/sis_mm.c | 8 ++--
drivers/gpu/drm/tegra/drm.c | 10 +++--
drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c | 3 +-
drivers/gpu/drm/vgem/vgem_fence.c | 12 +++---
drivers/gpu/drm/via/via_mm.c | 8 ++--
drivers/gpu/drm/virtio/virtgpu_kms.c | 5 ++-
drivers/gpu/drm/virtio/virtgpu_vq.c | 5 ++-
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 9 ++--
drivers/i2c/i2c-core-base.c | 19 +++++----
drivers/infiniband/core/cm.c | 8 ++--
drivers/infiniband/core/cma.c | 12 +++---
drivers/infiniband/core/rdma_core.c | 9 ++--
drivers/infiniband/core/sa_query.c | 23 +++++-----
drivers/infiniband/core/ucm.c | 7 ++-
drivers/infiniband/core/ucma.c | 14 ++++--
drivers/infiniband/hw/cxgb3/iwch.c | 4 +-
drivers/infiniband/hw/cxgb3/iwch.h | 4 +-
drivers/infiniband/hw/cxgb4/device.c | 18 ++++----
drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 4 +-
drivers/infiniband/hw/hfi1/init.c | 9 ++--
drivers/infiniband/hw/hfi1/vnic_main.c | 6 +--
drivers/infiniband/hw/mlx4/cm.c | 13 +++---
drivers/infiniband/hw/ocrdma/ocrdma_main.c | 7 ++-
drivers/infiniband/hw/qib/qib_init.c | 9 ++--
drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c | 10 ++---
drivers/iommu/intel-svm.c | 9 ++--
drivers/md/dm.c | 13 +++---
drivers/memstick/core/memstick.c | 10 +++--
drivers/memstick/core/ms_block.c | 9 ++--
drivers/memstick/core/mspro_block.c | 12 ++++--
drivers/mfd/rtsx_pcr.c | 9 ++--
drivers/misc/c2port/core.c | 7 +--
drivers/misc/cxl/context.c | 8 ++--
drivers/misc/cxl/main.c | 15 ++++---
drivers/misc/mei/main.c | 8 ++--
drivers/misc/mic/scif/scif_api.c | 11 ++---
drivers/misc/mic/scif/scif_ports.c | 18 ++++----
drivers/misc/tifm_core.c | 9 ++--
drivers/mtd/mtdcore.c | 9 ++--
drivers/mtd/mtdcore.h | 2 +-
drivers/mtd/ubi/block.c | 7 ++-
drivers/net/ppp/ppp_generic.c | 27 ++++++------
drivers/net/tap.c | 10 +++--
drivers/net/wireless/ath/ath10k/htt.h | 3 +-
drivers/net/wireless/ath/ath10k/htt_tx.c | 22 ++++++----
drivers/net/wireless/ath/ath10k/mac.c | 2 +-
drivers/net/wireless/marvell/mwifiex/main.c | 13 +++---
drivers/net/wireless/marvell/mwifiex/wmm.c | 2 +-
drivers/of/overlay.c | 15 +++----
drivers/of/unittest.c | 25 ++++++-----
drivers/power/supply/bq2415x_charger.c | 16 +++----
drivers/power/supply/bq27xxx_battery_i2c.c | 15 ++++---
drivers/power/supply/ds2782_battery.c | 9 ++--
drivers/powercap/powercap_sys.c | 8 ++--
drivers/pps/pps.c | 10 +++--
drivers/rapidio/rio_cm.c | 17 ++++----
drivers/remoteproc/remoteproc_core.c | 8 ++--
drivers/rpmsg/virtio_rpmsg_bus.c | 8 ++--
drivers/scsi/bfa/bfad_im.c | 8 ++--
drivers/scsi/ch.c | 8 ++--
drivers/scsi/lpfc/lpfc_crtn.h | 2 +-
drivers/scsi/lpfc/lpfc_init.c | 11 +++--
drivers/scsi/lpfc/lpfc_vport.c | 8 ++--
drivers/scsi/sg.c | 10 +++--
drivers/scsi/st.c | 8 ++--
drivers/staging/greybus/uart.c | 22 +++++-----
drivers/staging/unisys/visorhba/visorhba_main.c | 7 +--
drivers/target/iscsi/iscsi_target.c | 7 +--
drivers/target/iscsi/iscsi_target_login.c | 9 ++--
drivers/target/target_core_device.c | 9 ++--
drivers/target/target_core_user.c | 13 +++---
drivers/tee/tee_shm.c | 8 ++--
drivers/uio/uio.c | 9 ++--
drivers/usb/class/cdc-acm.c | 24 ++++++-----
drivers/usb/core/devices.c | 2 +-
drivers/usb/core/hcd.c | 7 +--
drivers/usb/mon/mon_main.c | 3 +-
drivers/usb/serial/usb-serial.c | 11 ++---
drivers/vfio/vfio.c | 15 ++++---
fs/dlm/lock.c | 9 ++--
fs/dlm/lockspace.c | 6 +--
fs/dlm/recover.c | 10 ++---
fs/nfs/nfs4client.c | 9 ++--
fs/nfsd/nfs4state.c | 8 ++--
fs/notify/inotify/inotify_fsnotify.c | 4 +-
fs/notify/inotify/inotify_user.c | 9 ++--
fs/ocfs2/cluster/tcp.c | 10 +++--
include/linux/idr.h | 26 +++++------
include/linux/of.h | 4 +-
include/linux/radix-tree.h | 2 +-
include/net/9p/9p.h | 2 +-
ipc/msg.c | 2 +-
ipc/sem.c | 2 +-
ipc/shm.c | 4 +-
ipc/util.c | 17 ++++----
kernel/bpf/syscall.c | 20 +++++----
kernel/cgroup/cgroup.c | 57 +++++++++++++++----------
kernel/events/core.c | 10 ++---
kernel/workqueue.c | 15 ++++---
lib/idr.c | 38 ++++++++++-------
lib/radix-tree.c | 5 ++-
mm/memcontrol.c | 11 +++--
net/9p/client.c | 17 ++++----
net/9p/util.c | 14 +++---
net/core/net_namespace.c | 23 +++++-----
net/mac80211/cfg.c | 23 +++++-----
net/mac80211/iface.c | 3 +-
net/mac80211/main.c | 2 +-
net/mac80211/tx.c | 7 +--
net/mac80211/util.c | 3 +-
net/netlink/genetlink.c | 18 ++++----
net/qrtr/qrtr.c | 21 +++++----
net/rxrpc/conn_client.c | 15 ++++---
net/sctp/associola.c | 8 ++--
net/tipc/server.c | 7 +--
153 files changed, 956 insertions(+), 736 deletions(-)
diff --git a/block/bsg.c b/block/bsg.c
index 37663b6..c2969af 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -981,6 +981,7 @@ int bsg_register_queue(struct request_queue *q, struct device *parent,
int ret;
struct device *class_dev = NULL;
const char *devname;
+ unsigned long idr_index;
if (name)
devname = name;
@@ -998,8 +999,9 @@ int bsg_register_queue(struct request_queue *q, struct device *parent,
mutex_lock(&bsg_mutex);
- ret = idr_alloc(&bsg_minor_idr, bcd, 0, BSG_MAX_DEVS, GFP_KERNEL);
- if (ret < 0) {
+ ret = idr_alloc(&bsg_minor_idr, bcd, &idr_index, 0, BSG_MAX_DEVS,
+ GFP_KERNEL);
+ if (ret) {
if (ret == -ENOSPC) {
printk(KERN_ERR "bsg: too many bsg devices\n");
ret = -EINVAL;
@@ -1007,7 +1009,7 @@ int bsg_register_queue(struct request_queue *q, struct device *parent,
goto unlock;
}
- bcd->minor = ret;
+ bcd->minor = idr_index;
bcd->queue = q;
bcd->parent = get_device(parent);
bcd->release = release;
diff --git a/block/genhd.c b/block/genhd.c
index 7f520fa..1f7d7c3 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -414,7 +414,8 @@ static int blk_mangle_minor(int minor)
int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
{
struct gendisk *disk = part_to_disk(part);
- int idx;
+ unsigned long idr_index;
+ int ret;
/* in consecutive minor range? */
if (part->partno < disk->minors) {
@@ -426,14 +427,15 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
idr_preload(GFP_KERNEL);
spin_lock_bh(&ext_devt_lock);
- idx = idr_alloc(&ext_devt_idr, part, 0, NR_EXT_DEVT, GFP_NOWAIT);
+ ret = idr_alloc(&ext_devt_idr, part, &idr_index, 0, NR_EXT_DEVT,
+ GFP_NOWAIT);
spin_unlock_bh(&ext_devt_lock);
idr_preload_end();
- if (idx < 0)
- return idx == -ENOSPC ? -EBUSY : idx;
+ if (ret)
+ return ret == -ENOSPC ? -EBUSY : ret;
- *devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx));
+ *devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idr_index));
return 0;
}
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index a970283..92b9ba5 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -943,7 +943,8 @@ static void free_scq(ns_dev *card, scq_info *scq, struct atm_vcc *vcc)
static void push_rxbufs(ns_dev * card, struct sk_buff *skb)
{
struct sk_buff *handle1, *handle2;
- int id1, id2;
+ int ret;
+ unsigned long id1, id2;
u32 addr1, addr2;
u32 stat;
unsigned long flags;
@@ -1019,12 +1020,12 @@ static void push_rxbufs(ns_dev * card, struct sk_buff *skb)
card->lbfqc += 2;
}
- id1 = idr_alloc(&card->idr, handle1, 0, 0, GFP_ATOMIC);
- if (id1 < 0)
+ ret = idr_alloc(&card->idr, handle1, &id1, 0, 0, GFP_ATOMIC);
+ if (ret)
goto out;
- id2 = idr_alloc(&card->idr, handle2, 0, 0, GFP_ATOMIC);
- if (id2 < 0)
+ ret = idr_alloc(&card->idr, handle2, &id2, 0, 0, GFP_ATOMIC);
+ if (ret)
goto out;
spin_lock_irqsave(&card->res_lock, flags);
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index e2ed28d..4ee5a91 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -489,7 +489,8 @@ void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait)
int conn_lowest_minor(struct drbd_connection *connection)
{
struct drbd_peer_device *peer_device;
- int vnr = 0, minor = -1;
+ int minor = -1;
+ unsigned long vnr = 0;
rcu_read_lock();
peer_device = idr_get_next(&connection->peer_devices, &vnr);
@@ -2390,7 +2391,7 @@ void drbd_free_resource(struct drbd_resource *resource)
static void drbd_cleanup(void)
{
- unsigned int i;
+ unsigned long i;
struct drbd_device *device;
struct drbd_resource *resource, *tmp;
@@ -2794,7 +2795,8 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
struct drbd_peer_device *peer_device, *tmp_peer_device;
struct gendisk *disk;
struct request_queue *q;
- int id;
+ int ret;
+ unsigned long idr_index;
int vnr = adm_ctx->volume;
enum drbd_ret_code err = ERR_NOMEM;
@@ -2858,17 +2860,19 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
device->read_requests = RB_ROOT;
device->write_requests = RB_ROOT;
- id = idr_alloc(&drbd_devices, device, minor, minor + 1, GFP_KERNEL);
- if (id < 0) {
- if (id == -ENOSPC)
+ ret = idr_alloc(&drbd_devices, device, &idr_index, minor, minor + 1,
+ GFP_KERNEL);
+ if (ret) {
+ if (ret == -ENOSPC)
err = ERR_MINOR_OR_VOLUME_EXISTS;
goto out_no_minor_idr;
}
kref_get(&device->kref);
- id = idr_alloc(&resource->devices, device, vnr, vnr + 1, GFP_KERNEL);
- if (id < 0) {
- if (id == -ENOSPC)
+ ret = idr_alloc(&resource->devices, device, &idr_index, vnr, vnr + 1,
+ GFP_KERNEL);
+ if (ret) {
+ if (ret == -ENOSPC)
err = ERR_MINOR_OR_VOLUME_EXISTS;
goto out_idr_remove_minor;
}
@@ -2886,9 +2890,10 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
list_add(&peer_device->peer_devices, &device->peer_devices);
kref_get(&device->kref);
- id = idr_alloc(&connection->peer_devices, peer_device, vnr, vnr + 1, GFP_KERNEL);
- if (id < 0) {
- if (id == -ENOSPC)
+ ret = idr_alloc(&connection->peer_devices, peer_device,
+ &idr_index, vnr, vnr + 1, GFP_KERNEL);
+ if (ret) {
+ if (ret == -ENOSPC)
err = ERR_INVALID_REQUEST;
goto out_idr_remove_from_resource;
}
@@ -3072,7 +3077,7 @@ void drbd_free_sock(struct drbd_connection *connection)
void conn_md_sync(struct drbd_connection *connection)
{
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index ad0fcb4..913adf5 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -428,7 +428,7 @@ static enum drbd_fencing_p highest_fencing_policy(struct drbd_connection *connec
{
enum drbd_fencing_p fp = FP_NOT_AVAIL;
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
@@ -2209,7 +2209,7 @@ static bool conn_resync_running(struct drbd_connection *connection)
{
struct drbd_peer_device *peer_device;
bool rv = false;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
@@ -2231,7 +2231,7 @@ static bool conn_ov_running(struct drbd_connection *connection)
{
struct drbd_peer_device *peer_device;
bool rv = false;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
@@ -2251,7 +2251,7 @@ static bool conn_ov_running(struct drbd_connection *connection)
_check_net_options(struct drbd_connection *connection, struct net_conf *old_net_conf, struct net_conf *new_net_conf)
{
struct drbd_peer_device *peer_device;
- int i;
+ unsigned long i;
if (old_net_conf && connection->cstate == C_WF_REPORT_PARAMS && connection->agreed_pro_version < 100) {
if (new_net_conf->wire_protocol != old_net_conf->wire_protocol)
@@ -2488,7 +2488,7 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
if (connection->cstate >= C_WF_REPORT_PARAMS) {
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
idr_for_each_entry(&connection->peer_devices, peer_device, vnr)
drbd_send_sync_param(peer_device);
@@ -2542,7 +2542,7 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
struct drbd_resource *resource;
struct drbd_connection *connection;
enum drbd_ret_code retcode;
- int i;
+ unsigned long i;
int err;
retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE);
@@ -3382,7 +3382,8 @@ int drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb)
struct nlattr *resource_filter;
struct drbd_resource *resource;
struct drbd_device *uninitialized_var(device);
- int minor, err, retcode;
+ int err, retcode;
+ unsigned long minor;
struct drbd_genlmsghdr *dh;
struct device_info device_info;
struct device_statistics device_statistics;
@@ -3634,7 +3635,8 @@ int drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb)
struct drbd_resource *resource;
struct drbd_device *uninitialized_var(device);
struct drbd_peer_device *peer_device = NULL;
- int minor, err, retcode;
+ int err, retcode;
+ unsigned long minor;
struct drbd_genlmsghdr *dh;
struct idr *idr_to_search;
@@ -3887,7 +3889,7 @@ static int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
struct drbd_resource *pos = (struct drbd_resource *)cb->args[0];
struct drbd_resource *resource = NULL;
struct drbd_resource *tmp;
- unsigned volume = cb->args[1];
+ unsigned long volume = cb->args[1];
/* Open coded, deferred, iteration:
* for_each_resource_safe(resource, tmp, &drbd_resources) {
@@ -4464,7 +4466,7 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
struct drbd_connection *connection;
struct drbd_device *device;
int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
- unsigned i;
+ unsigned long i;
retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE);
if (!adm_ctx.reply_skb)
diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c
index 8378142..1c9c5b8 100644
--- a/drivers/block/drbd/drbd_proc.c
+++ b/drivers/block/drbd/drbd_proc.c
@@ -237,7 +237,8 @@ static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *se
static int drbd_seq_show(struct seq_file *seq, void *v)
{
- int i, prev_i = -1;
+ int prev_i = -1;
+ unsigned long i;
const char *sn;
struct drbd_device *device;
struct net_conf *nc;
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index c7e95e6..64ab66e 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -232,7 +232,7 @@ static void drbd_reclaim_net_peer_reqs(struct drbd_device *device)
static void conn_reclaim_net_peer_reqs(struct drbd_connection *connection)
{
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
@@ -934,7 +934,8 @@ static int conn_connect(struct drbd_connection *connection)
struct drbd_socket sock, msock;
struct drbd_peer_device *peer_device;
struct net_conf *nc;
- int vnr, timeout, h;
+ int timeout, h;
+ unsigned long vnr;
bool discard_my_data, ok;
enum drbd_state_rv rv;
struct accept_wait_data ad = {
@@ -1281,7 +1282,7 @@ static void drbd_flush(struct drbd_connection *connection)
if (connection->resource->write_ordering >= WO_BDEV_FLUSH) {
struct drbd_peer_device *peer_device;
struct issue_flush_context ctx;
- int vnr;
+ unsigned long vnr;
atomic_set(&ctx.pending, 1);
ctx.error = 0;
@@ -1418,7 +1419,7 @@ void drbd_bump_write_ordering(struct drbd_resource *resource, struct drbd_backin
{
struct drbd_device *device;
enum write_ordering_e pwo;
- int vnr;
+ unsigned long vnr;
static char *write_ordering_str[] = {
[WO_NONE] = "none",
[WO_DRAIN_IO] = "drain",
@@ -1606,7 +1607,7 @@ static void drbd_remove_epoch_entry_interval(struct drbd_device *device,
static void conn_wait_active_ee_empty(struct drbd_connection *connection)
{
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
@@ -4933,7 +4934,7 @@ static void conn_disconnect(struct drbd_connection *connection)
{
struct drbd_peer_device *peer_device;
enum drbd_conns oc;
- int vnr;
+ unsigned long vnr;
if (connection->cstate == C_STANDALONE)
return;
@@ -5644,7 +5645,7 @@ static int got_BarrierAck(struct drbd_connection *connection, struct packet_info
{
struct p_barrier_ack *p = pi->data;
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
tl_release(connection, p->barrier, be32_to_cpu(p->set_size));
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c
index eea0c4a..d6566d0 100644
--- a/drivers/block/drbd/drbd_state.c
+++ b/drivers/block/drbd/drbd_state.c
@@ -56,7 +56,7 @@ static void count_objects(struct drbd_resource *resource,
{
struct drbd_device *device;
struct drbd_connection *connection;
- int vnr;
+ unsigned long vnr;
*n_devices = 0;
*n_connections = 0;
@@ -99,7 +99,7 @@ struct drbd_state_change *remember_old_state(struct drbd_resource *resource, gfp
unsigned int n_devices;
struct drbd_connection *connection;
unsigned int n_connections;
- int vnr;
+ unsigned long vnr;
struct drbd_device_state_change *device_state_change;
struct drbd_peer_device_state_change *peer_device_state_change;
@@ -307,7 +307,7 @@ bool conn_all_vols_unconf(struct drbd_connection *connection)
{
struct drbd_peer_device *peer_device;
bool rv = true;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
@@ -348,7 +348,7 @@ enum drbd_role conn_highest_role(struct drbd_connection *connection)
{
enum drbd_role role = R_UNKNOWN;
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
@@ -364,7 +364,7 @@ enum drbd_role conn_highest_peer(struct drbd_connection *connection)
{
enum drbd_role peer = R_UNKNOWN;
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
@@ -380,7 +380,7 @@ enum drbd_disk_state conn_highest_disk(struct drbd_connection *connection)
{
enum drbd_disk_state disk_state = D_DISKLESS;
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
@@ -396,7 +396,7 @@ enum drbd_disk_state conn_lowest_disk(struct drbd_connection *connection)
{
enum drbd_disk_state disk_state = D_MASK;
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
@@ -412,7 +412,7 @@ enum drbd_disk_state conn_highest_pdsk(struct drbd_connection *connection)
{
enum drbd_disk_state disk_state = D_DISKLESS;
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
@@ -428,7 +428,7 @@ enum drbd_conns conn_lowest_conn(struct drbd_connection *connection)
{
enum drbd_conns conn = C_MASK;
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
@@ -443,7 +443,7 @@ enum drbd_conns conn_lowest_conn(struct drbd_connection *connection)
static bool no_peer_wf_report_params(struct drbd_connection *connection)
{
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
bool rv = true;
rcu_read_lock();
@@ -460,7 +460,7 @@ static bool no_peer_wf_report_params(struct drbd_connection *connection)
static void wake_up_all_devices(struct drbd_connection *connection)
{
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr)
@@ -1723,7 +1723,7 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os,
if (resource->susp_fen && conn_lowest_conn(connection) >= C_CONNECTED) {
/* case2: The connection was established again: */
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr)
@@ -2010,7 +2010,7 @@ static int w_after_conn_state_ch(struct drbd_work *w, int unused)
enum drbd_conns oc = acscw->oc;
union drbd_state ns_max = acscw->ns_max;
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
broadcast_state_change(acscw->state_change);
forget_state_change(acscw->state_change);
@@ -2074,7 +2074,8 @@ static void conn_old_common_state(struct drbd_connection *connection, union drbd
{
enum chg_state_flags flags = ~0;
struct drbd_peer_device *peer_device;
- int vnr, first_vol = 1;
+ int first_vol = 1;
+ unsigned long vnr;
union drbd_dev_state os, cs = {
{ .role = R_SECONDARY,
.peer = R_UNKNOWN,
@@ -2123,7 +2124,7 @@ static void conn_old_common_state(struct drbd_connection *connection, union drbd
enum drbd_state_rv rv = SS_SUCCESS;
union drbd_state ns, os;
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
@@ -2173,7 +2174,8 @@ static void conn_old_common_state(struct drbd_connection *connection, union drbd
} };
struct drbd_peer_device *peer_device;
enum drbd_state_rv rv;
- int vnr, number_of_volumes = 0;
+ int number_of_volumes = 0;
+ unsigned long vnr;
if (mask.conn == C_MASK) {
/* remember last connect time so request_timer_fn() won't
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
index 1d8726a..8129b00 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -1553,7 +1553,7 @@ static bool drbd_pause_after(struct drbd_device *device)
{
bool changed = false;
struct drbd_device *odev;
- int i;
+ unsigned long i;
rcu_read_lock();
idr_for_each_entry(&drbd_devices, odev, i) {
@@ -2035,7 +2035,7 @@ static unsigned long get_work_bits(unsigned long *flags)
static void do_unqueued_work(struct drbd_connection *connection)
{
struct drbd_peer_device *peer_device;
- int vnr;
+ unsigned long vnr;
rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
@@ -2152,7 +2152,7 @@ int drbd_worker(struct drbd_thread *thi)
struct drbd_work *w = NULL;
struct drbd_peer_device *peer_device;
LIST_HEAD(work_list);
- int vnr;
+ unsigned long vnr;
while (get_t_state(thi) == RUNNING) {
drbd_thread_current_set_cpu(thi);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index ef83349..6308b44 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1655,7 +1655,7 @@ int loop_register_transfer(struct loop_func_table *funcs)
return 0;
}
-static int unregister_transfer_cb(int id, void *ptr, void *data)
+static int unregister_transfer_cb(unsigned long id, void *ptr, void *data)
{
struct loop_device *lo = ptr;
struct loop_func_table *xfer = data;
@@ -1759,6 +1759,7 @@ static int loop_add(struct loop_device **l, int i)
{
struct loop_device *lo;
struct gendisk *disk;
+ unsigned long idr_index;
int err;
err = -ENOMEM;
@@ -1770,15 +1771,17 @@ static int loop_add(struct loop_device **l, int i)
/* allocate id, if @id >= 0, we're requesting that specific id */
if (i >= 0) {
- err = idr_alloc(&loop_index_idr, lo, i, i + 1, GFP_KERNEL);
+ err = idr_alloc(&loop_index_idr, lo, &idr_index, i, i + 1,
+ GFP_KERNEL);
if (err == -ENOSPC)
err = -EEXIST;
} else {
- err = idr_alloc(&loop_index_idr, lo, 0, 0, GFP_KERNEL);
+ err = idr_alloc(&loop_index_idr, lo, &idr_index, 0, 0,
+ GFP_KERNEL);
}
- if (err < 0)
+ if (err)
goto out_free_dev;
- i = err;
+ i = idr_index;
err = -ENOMEM;
lo->tag_set.ops = &loop_mq_ops;
@@ -1867,7 +1870,7 @@ static void loop_remove(struct loop_device *lo)
kfree(lo);
}
-static int find_free_cb(int id, void *ptr, void *data)
+static int find_free_cb(unsigned long id, void *ptr, void *data)
{
struct loop_device *lo = ptr;
struct loop_device **l = data;
@@ -2063,7 +2066,7 @@ static int __init loop_init(void)
return err;
}
-static int loop_exit_cb(int id, void *ptr, void *data)
+static int loop_exit_cb(unsigned long id, void *ptr, void *data)
{
struct loop_device *lo = ptr;
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 5bdf923..f55b695 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -1427,6 +1427,7 @@ static int nbd_dev_add(int index)
struct nbd_device *nbd;
struct gendisk *disk;
struct request_queue *q;
+ unsigned long idr_index;
int err = -ENOMEM;
nbd = kzalloc(sizeof(struct nbd_device), GFP_KERNEL);
@@ -1438,16 +1439,17 @@ static int nbd_dev_add(int index)
goto out_free_nbd;
if (index >= 0) {
- err = idr_alloc(&nbd_index_idr, nbd, index, index + 1,
- GFP_KERNEL);
+ err = idr_alloc(&nbd_index_idr, nbd, &idr_index,
+ index, index + 1, GFP_KERNEL);
if (err == -ENOSPC)
err = -EEXIST;
} else {
- err = idr_alloc(&nbd_index_idr, nbd, 0, 0, GFP_KERNEL);
- if (err >= 0)
- index = err;
+ err = idr_alloc(&nbd_index_idr, nbd, &idr_index,
+ 0, 0, GFP_KERNEL);
+ if (err == 0)
+ index = idr_index;
}
- if (err < 0)
+ if (err)
goto out_free_disk;
nbd->index = index;
@@ -1509,7 +1511,7 @@ static int nbd_dev_add(int index)
return err;
}
-static int find_free_cb(int id, void *ptr, void *data)
+static int find_free_cb(unsigned long id, void *ptr, void *data)
{
struct nbd_device *nbd = ptr;
struct nbd_device **found = data;
@@ -1922,7 +1924,7 @@ static int populate_nbd_status(struct nbd_device *nbd, struct sk_buff *reply)
return 0;
}
-static int status_cb(int id, void *ptr, void *data)
+static int status_cb(unsigned long id, void *ptr, void *data)
{
struct nbd_device *nbd = ptr;
return populate_nbd_status(nbd, (struct sk_buff *)data);
@@ -2094,7 +2096,7 @@ static int __init nbd_init(void)
return 0;
}
-static int nbd_exit_cb(int id, void *ptr, void *data)
+static int nbd_exit_cb(unsigned long id, void *ptr, void *data)
{
struct list_head *list = (struct list_head *)data;
struct nbd_device *nbd = ptr;
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 856d5dc02..7b4d9fb 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1137,15 +1137,16 @@ static int zram_add(void)
struct zram *zram;
struct request_queue *queue;
int ret, device_id;
+ unsigned long idr_index;
zram = kzalloc(sizeof(struct zram), GFP_KERNEL);
if (!zram)
return -ENOMEM;
- ret = idr_alloc(&zram_index_idr, zram, 0, 0, GFP_KERNEL);
- if (ret < 0)
+ ret = idr_alloc(&zram_index_idr, zram, &idr_index, 0, 0, GFP_KERNEL);
+ if (ret)
goto out_free_dev;
- device_id = ret;
+ device_id = idr_index;
init_rwsem(&zram->init_lock);
@@ -1341,7 +1342,7 @@ static ssize_t hot_remove_store(struct class *class,
.class_groups = zram_control_class_groups,
};
-static int zram_remove_cb(int id, void *ptr, void *data)
+static int zram_remove_cb(unsigned long id, void *ptr, void *data)
{
zram_remove(ptr);
return 0;
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 67ec9d3..70cea3c 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -86,7 +86,7 @@ void tpm_put_ops(struct tpm_chip *chip)
* The return'd chip has been tpm_try_get_ops'd and must be released via
* tpm_put_ops
*/
-struct tpm_chip *tpm_chip_find_get(int chip_num)
+struct tpm_chip *tpm_chip_find_get(unsigned long chip_num)
{
struct tpm_chip *chip, *res = NULL;
int chip_prev;
@@ -189,6 +189,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
const struct tpm_class_ops *ops)
{
struct tpm_chip *chip;
+ unsigned long idr_index;
int rc;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
@@ -201,14 +202,15 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
chip->ops = ops;
mutex_lock(&idr_lock);
- rc = idr_alloc(&dev_nums_idr, NULL, 0, TPM_NUM_DEVICES, GFP_KERNEL);
+ rc = idr_alloc(&dev_nums_idr, NULL, &idr_index, 0, TPM_NUM_DEVICES,
+ GFP_KERNEL);
mutex_unlock(&idr_lock);
- if (rc < 0) {
+ if (rc) {
dev_err(pdev, "No available tpm device numbers\n");
kfree(chip);
return ERR_PTR(rc);
}
- chip->dev_num = rc;
+ chip->dev_num = idr_index;
device_initialize(&chip->dev);
device_initialize(&chip->devs);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 04fbff2..5e6538b 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -527,7 +527,7 @@ ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
wait_queue_head_t *queue, bool check_cancel);
-struct tpm_chip *tpm_chip_find_get(int chip_num);
+struct tpm_chip *tpm_chip_find_get(unsigned long chip_num);
__must_check int tpm_try_get_ops(struct tpm_chip *chip);
void tpm_put_ops(struct tpm_chip *chip);
diff --git a/drivers/dca/dca-sysfs.c b/drivers/dca/dca-sysfs.c
index 126cf29..93a7798 100644
--- a/drivers/dca/dca-sysfs.c
+++ b/drivers/dca/dca-sysfs.c
@@ -53,18 +53,19 @@ void dca_sysfs_remove_req(struct dca_provider *dca, int slot)
int dca_sysfs_add_provider(struct dca_provider *dca, struct device *dev)
{
struct device *cd;
+ unsigned long idr_index;
int ret;
idr_preload(GFP_KERNEL);
spin_lock(&dca_idr_lock);
- ret = idr_alloc(&dca_idr, dca, 0, 0, GFP_NOWAIT);
- if (ret >= 0)
- dca->id = ret;
+ ret = idr_alloc(&dca_idr, dca, &idr_index, 0, 0, GFP_NOWAIT);
+ if (ret == 0)
+ dca->id = idr_index;
spin_unlock(&dca_idr_lock);
idr_preload_end();
- if (ret < 0)
+ if (ret)
return ret;
cd = device_create(dca_class, dev, MKDEV(0, 0), NULL, "dca%d", dca->id);
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index a301fcf..162c2b5 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -378,7 +378,7 @@ static void for_each_client(struct fw_device *device,
mutex_unlock(&device->client_list_mutex);
}
-static int schedule_reallocations(int id, void *p, void *data)
+static int schedule_reallocations(unsigned long id, void *p, void *data)
{
schedule_if_iso_resource(p);
@@ -488,6 +488,7 @@ static int add_client_resource(struct client *client,
{
bool preload = gfpflags_allow_blocking(gfp_mask);
unsigned long flags;
+ unsigned long idr_index;
int ret;
if (preload)
@@ -497,10 +498,10 @@ static int add_client_resource(struct client *client,
if (client->in_shutdown)
ret = -ECANCELED;
else
- ret = idr_alloc(&client->resource_idr, resource, 0, 0,
- GFP_NOWAIT);
- if (ret >= 0) {
- resource->handle = ret;
+ ret = idr_alloc(&client->resource_idr, resource, &idr_index,
+ 0, 0, GFP_NOWAIT);
+ if (ret == 0) {
+ resource->handle = idr_index;
client_get(client);
schedule_if_iso_resource(resource);
}
@@ -509,7 +510,7 @@ static int add_client_resource(struct client *client,
if (preload)
idr_preload_end();
- return ret < 0 ? ret : 0;
+ return ret;
}
static int release_client_resource(struct client *client, u32 handle,
@@ -1717,7 +1718,8 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
return ret;
}
-static int is_outbound_transaction_resource(int id, void *p, void *data)
+static int is_outbound_transaction_resource(unsigned long id, void *p,
+ void *data)
{
struct client_resource *resource = p;
@@ -1736,7 +1738,7 @@ static int has_outbound_transactions(struct client *client)
return ret;
}
-static int shutdown_resource(int id, void *p, void *data)
+static int shutdown_resource(unsigned long id, void *p, void *data)
{
struct client_resource *resource = p;
struct client *client = data;
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index 7c2eed7..2fe2e67 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -1000,7 +1000,8 @@ static void fw_device_init(struct work_struct *work)
container_of(work, struct fw_device, work.work);
struct fw_card *card = device->card;
struct device *revived_dev;
- int minor, ret;
+ int ret;
+ unsigned long idr_index;
/*
* All failure paths here set node->data to NULL, so that we
@@ -1039,18 +1040,18 @@ static void fw_device_init(struct work_struct *work)
fw_device_get(device);
down_write(&fw_device_rwsem);
- minor = idr_alloc(&fw_device_idr, device, 0, 1 << MINORBITS,
- GFP_KERNEL);
+ ret = idr_alloc(&fw_device_idr, device, &idr_index,
+ 0, 1 << MINORBITS, GFP_KERNEL);
up_write(&fw_device_rwsem);
- if (minor < 0)
+ if (ret)
goto error;
device->device.bus = &fw_bus_type;
device->device.type = &fw_device_type;
device->device.parent = card->device;
- device->device.devt = MKDEV(fw_cdev_major, minor);
- dev_set_name(&device->device, "fw%d", minor);
+ device->device.devt = MKDEV(fw_cdev_major, idr_index);
+ dev_set_name(&device->device, "fw%ld", idr_index);
BUILD_BUG_ON(ARRAY_SIZE(device->attribute_group.attrs) <
ARRAY_SIZE(fw_device_attributes) +
@@ -1105,7 +1106,7 @@ static void fw_device_init(struct work_struct *work)
error_with_cdev:
down_write(&fw_device_rwsem);
- idr_remove(&fw_device_idr, minor);
+ idr_remove(&fw_device_idr, idr_index);
up_write(&fw_device_rwsem);
error:
fw_device_put(device); /* fw_device_idr's reference */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
index 5e771bc..617e6aa 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
@@ -62,6 +62,7 @@ static int amdgpu_bo_list_create(struct amdgpu_device *adev,
int *id)
{
int r;
+ unsigned long idr_index;
struct amdgpu_fpriv *fpriv = filp->driver_priv;
struct amdgpu_bo_list *list;
@@ -80,13 +81,14 @@ static int amdgpu_bo_list_create(struct amdgpu_device *adev,
/* idr alloc should be called only after initialization of bo list. */
mutex_lock(&fpriv->bo_list_lock);
- r = idr_alloc(&fpriv->bo_list_handles, list, 1, 0, GFP_KERNEL);
+ r = idr_alloc(&fpriv->bo_list_handles, list, &idr_index, 1, 0,
+ GFP_KERNEL);
mutex_unlock(&fpriv->bo_list_lock);
- if (r < 0) {
+ if (r) {
kfree(list);
return r;
}
- *id = r;
+ *id = idr_index;
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
index a11e443..4117764 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
@@ -104,6 +104,7 @@ static int amdgpu_ctx_alloc(struct amdgpu_device *adev,
{
struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
struct amdgpu_ctx *ctx;
+ unsigned long idr_index;
int r;
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
@@ -111,13 +112,13 @@ static int amdgpu_ctx_alloc(struct amdgpu_device *adev,
return -ENOMEM;
mutex_lock(&mgr->lock);
- r = idr_alloc(&mgr->ctx_handles, ctx, 1, 0, GFP_KERNEL);
- if (r < 0) {
+ r = idr_alloc(&mgr->ctx_handles, ctx, &idr_index, 1, 0, GFP_KERNEL);
+ if (r) {
mutex_unlock(&mgr->lock);
kfree(ctx);
return r;
}
- *id = (uint32_t)r;
+ *id = (uint32_t)idr_index;
r = amdgpu_ctx_init(adev, ctx);
if (r) {
idr_remove(&mgr->ctx_handles, *id);
@@ -313,7 +314,7 @@ void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr)
{
struct amdgpu_ctx *ctx;
struct idr *idp;
- uint32_t id;
+ unsigned long id;
idp = &mgr->ctx_handles;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index 621f739..698a0b1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -97,7 +97,7 @@ void amdgpu_gem_force_release(struct amdgpu_device *adev)
list_for_each_entry(file, &ddev->filelist, lhead) {
struct drm_gem_object *gobj;
- int handle;
+ unsigned long handle;
WARN_ONCE(1, "Still active user space clients!\n");
spin_lock(&file->table_lock);
@@ -775,7 +775,7 @@ int amdgpu_mode_dumb_create(struct drm_file *file_priv,
}
#if defined(CONFIG_DEBUG_FS)
-static int amdgpu_debugfs_gem_bo_info(int id, void *ptr, void *data)
+static int amdgpu_debugfs_gem_bo_info(unsigned long id, void *ptr, void *data)
{
struct drm_gem_object *gobj = ptr;
struct amdgpu_bo *bo = gem_to_amdgpu_bo(gobj);
@@ -798,7 +798,7 @@ static int amdgpu_debugfs_gem_bo_info(int id, void *ptr, void *data)
placement = " CPU";
break;
}
- seq_printf(m, "\t0x%08x: %12ld byte %s @ 0x%010Lx",
+ seq_printf(m, "\t0x%08lx: %12ld byte %s @ 0x%010llx",
id, amdgpu_bo_size(bo), placement,
amdgpu_bo_gpu_offset(bo));
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index b0b2310..0074dd6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -873,7 +873,7 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
struct amdgpu_device *adev = dev->dev_private;
struct amdgpu_fpriv *fpriv = file_priv->driver_priv;
struct amdgpu_bo_list *list;
- int handle;
+ unsigned long handle;
if (!fpriv)
return;
diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
index 7ff6973..345ff34 100644
--- a/drivers/gpu/drm/drm_auth.c
+++ b/drivers/gpu/drm/drm_auth.c
@@ -57,21 +57,22 @@
int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
struct drm_auth *auth = data;
+ unsigned long idr_index;
int ret = 0;
mutex_lock(&dev->master_mutex);
if (!file_priv->magic) {
ret = idr_alloc(&file_priv->master->magic_map, file_priv,
- 1, 0, GFP_KERNEL);
- if (ret >= 0)
- file_priv->magic = ret;
+ &idr_index, 1, 0, GFP_KERNEL);
+ if (ret == 0)
+ file_priv->magic = idr_index;
}
auth->magic = file_priv->magic;
mutex_unlock(&dev->master_mutex);
DRM_DEBUG("%u\n", auth->magic);
- return ret < 0 ? ret : 0;
+ return ret;
}
int drm_authmagic(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 8072e6e..555a598 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1431,7 +1431,7 @@ struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
char topology[8])
{
struct drm_tile_group *tg;
- int id;
+ unsigned long id;
mutex_lock(&dev->mode_config.idr_mutex);
idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) {
if (!memcmp(tg->group_data, topology, 8)) {
@@ -1461,6 +1461,7 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
char topology[8])
{
struct drm_tile_group *tg;
+ unsigned long idr_index;
int ret;
tg = kzalloc(sizeof(*tg), GFP_KERNEL);
@@ -1472,9 +1473,10 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
tg->dev = dev;
mutex_lock(&dev->mode_config.idr_mutex);
- ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL);
- if (ret >= 0) {
- tg->id = ret;
+ ret = idr_alloc(&dev->mode_config.tile_idr, tg, &idr_index, 1, 0,
+ GFP_KERNEL);
+ if (ret == 0) {
+ tg->id = idr_index;
} else {
kfree(tg);
tg = ERR_PTR(ret);
diff --git a/drivers/gpu/drm/drm_context.c b/drivers/gpu/drm/drm_context.c
index 3c4000f..cc983c2 100644
--- a/drivers/gpu/drm/drm_context.c
+++ b/drivers/gpu/drm/drm_context.c
@@ -71,13 +71,14 @@ void drm_legacy_ctxbitmap_free(struct drm_device * dev, int ctx_handle)
* Allocate a new idr from drm_device::ctx_idr while holding the
* drm_device::struct_mutex lock.
*/
-static int drm_legacy_ctxbitmap_next(struct drm_device * dev)
+static int drm_legacy_ctxbitmap_next(struct drm_device *dev,
+ unsigned long *handle)
{
int ret;
mutex_lock(&dev->struct_mutex);
- ret = idr_alloc(&dev->ctx_idr, NULL, DRM_RESERVED_CONTEXTS, 0,
- GFP_KERNEL);
+ ret = idr_alloc(&dev->ctx_idr, NULL, handle,
+ DRM_RESERVED_CONTEXTS, 0, GFP_KERNEL);
mutex_unlock(&dev->struct_mutex);
return ret;
}
@@ -361,18 +362,21 @@ int drm_legacy_addctx(struct drm_device *dev, void *data,
{
struct drm_ctx_list *ctx_entry;
struct drm_ctx *ctx = data;
+ unsigned long handle;
+ int ret;
if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
!drm_core_check_feature(dev, DRIVER_LEGACY))
return -EINVAL;
- ctx->handle = drm_legacy_ctxbitmap_next(dev);
- if (ctx->handle == DRM_KERNEL_CONTEXT) {
+ ret = drm_legacy_ctxbitmap_next(dev, &handle);
+ if (handle == DRM_KERNEL_CONTEXT) {
/* Skip kernel's context and get a new one. */
- ctx->handle = drm_legacy_ctxbitmap_next(dev);
+ ret = drm_legacy_ctxbitmap_next(dev, &handle);
}
- DRM_DEBUG("%d\n", ctx->handle);
- if (ctx->handle == -1) {
+ ctx->handle = handle;
+ DRM_DEBUG("ret: %d, handle: %u\n", ret, ctx->handle);
+ if (ret) {
DRM_DEBUG("Not enough free contexts.\n");
/* Should this return -EBUSY instead? */
return -ENOMEM;
diff --git a/drivers/gpu/drm/drm_dp_aux_dev.c b/drivers/gpu/drm/drm_dp_aux_dev.c
index d34e509..89e8d16 100644
--- a/drivers/gpu/drm/drm_dp_aux_dev.c
+++ b/drivers/gpu/drm/drm_dp_aux_dev.c
@@ -70,7 +70,8 @@ static struct drm_dp_aux_dev *drm_dp_aux_dev_get_by_minor(unsigned index)
static struct drm_dp_aux_dev *alloc_drm_dp_aux_dev(struct drm_dp_aux *aux)
{
struct drm_dp_aux_dev *aux_dev;
- int index;
+ unsigned long index;
+ int ret;
aux_dev = kzalloc(sizeof(*aux_dev), GFP_KERNEL);
if (!aux_dev)
@@ -80,10 +81,10 @@ static struct drm_dp_aux_dev *alloc_drm_dp_aux_dev(struct drm_dp_aux *aux)
kref_init(&aux_dev->refcount);
mutex_lock(&aux_idr_mutex);
- index = idr_alloc_cyclic(&aux_idr, aux_dev, 0, DRM_AUX_MINORS,
- GFP_KERNEL);
+ ret = idr_alloc_cyclic(&aux_idr, aux_dev, &index, 0, DRM_AUX_MINORS,
+ GFP_KERNEL);
mutex_unlock(&aux_idr_mutex);
- if (index < 0) {
+ if (ret) {
kfree(aux_dev);
return ERR_PTR(index);
}
@@ -245,7 +246,7 @@ static int auxdev_release(struct inode *inode, struct file *file)
static struct drm_dp_aux_dev *drm_dp_aux_dev_get_by_aux(struct drm_dp_aux *aux)
{
struct drm_dp_aux_dev *iter, *aux_dev = NULL;
- int id;
+ unsigned long id;
/* don't increase kref count here because this function should only be
* used by drm_dp_aux_unregister_devnode. Thus, it will always have at
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 37b8ad3..d79b8b7 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -144,6 +144,7 @@ static int drm_minor_alloc(struct drm_device *dev, unsigned int type)
{
struct drm_minor *minor;
unsigned long flags;
+ unsigned long idr_index;
int r;
minor = kzalloc(sizeof(*minor), GFP_KERNEL);
@@ -157,16 +158,17 @@ static int drm_minor_alloc(struct drm_device *dev, unsigned int type)
spin_lock_irqsave(&drm_minor_lock, flags);
r = idr_alloc(&drm_minors_idr,
NULL,
+ &idr_index,
64 * type,
64 * (type + 1),
GFP_NOWAIT);
spin_unlock_irqrestore(&drm_minor_lock, flags);
idr_preload_end();
- if (r < 0)
+ if (r)
goto err_free;
- minor->index = r;
+ minor->index = idr_index;
minor->kdev = drm_sysfs_minor_alloc(minor);
if (IS_ERR(minor->kdev)) {
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 8dc1106..c618333 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -249,7 +249,7 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
* handle references on objects.
*/
static int
-drm_gem_object_release_handle(int id, void *ptr, void *data)
+drm_gem_object_release_handle(unsigned long id, void *ptr, void *data)
{
struct drm_file *file_priv = data;
struct drm_gem_object *obj = ptr;
@@ -347,7 +347,7 @@ int drm_gem_dumb_destroy(struct drm_file *file,
u32 *handlep)
{
struct drm_device *dev = obj->dev;
- u32 handle;
+ unsigned long handle;
int ret;
WARN_ON(!mutex_is_locked(&dev->object_name_lock));
@@ -361,17 +361,16 @@ int drm_gem_dumb_destroy(struct drm_file *file,
idr_preload(GFP_KERNEL);
spin_lock(&file_priv->table_lock);
- ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_NOWAIT);
+ ret = idr_alloc(&file_priv->object_idr, obj, &handle, 1, 0,
+ GFP_NOWAIT);
spin_unlock(&file_priv->table_lock);
idr_preload_end();
mutex_unlock(&dev->object_name_lock);
- if (ret < 0)
+ if (ret)
goto err_unref;
- handle = ret;
-
ret = drm_vma_node_allow(&obj->vma_node, file_priv);
if (ret)
goto err_remove;
@@ -654,6 +653,7 @@ struct drm_gem_object *
{
struct drm_gem_flink *args = data;
struct drm_gem_object *obj;
+ unsigned long idr_index;
int ret;
if (!drm_core_check_feature(dev, DRIVER_GEM))
@@ -671,11 +671,12 @@ struct drm_gem_object *
}
if (!obj->name) {
- ret = idr_alloc(&dev->object_name_idr, obj, 1, 0, GFP_KERNEL);
- if (ret < 0)
+ ret = idr_alloc(&dev->object_name_idr, obj, &idr_index,
+ 1, 0, GFP_KERNEL);
+ if (ret)
goto err;
- obj->name = ret;
+ obj->name = idr_index;
}
args->name = (uint64_t) obj->name;
diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c
index 6b68e90..5bcf144 100644
--- a/drivers/gpu/drm/drm_info.c
+++ b/drivers/gpu/drm/drm_info.c
@@ -110,7 +110,7 @@ int drm_clients_info(struct seq_file *m, void *data)
return 0;
}
-static int drm_gem_one_name_info(int id, void *ptr, void *data)
+static int drm_gem_one_name_info(unsigned long id, void *ptr, void *data)
{
struct drm_gem_object *obj = ptr;
struct seq_file *m = data;
diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c
index da9a9ad..72f70bc 100644
--- a/drivers/gpu/drm/drm_mode_object.c
+++ b/drivers/gpu/drm/drm_mode_object.c
@@ -36,15 +36,18 @@ int __drm_mode_object_add(struct drm_device *dev, struct drm_mode_object *obj,
void (*obj_free_cb)(struct kref *kref))
{
int ret;
+ unsigned long idr_index;
mutex_lock(&dev->mode_config.idr_mutex);
- ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL);
- if (ret >= 0) {
+ ret = idr_alloc(&dev->mode_config.crtc_idr,
+ register_obj ? obj : NULL, &idr_index, 1, 0,
+ GFP_KERNEL);
+ if (ret == 0) {
/*
* Set up the object linking under the protection of the idr
* lock so that other users can't see inconsistent state.
*/
- obj->id = ret;
+ obj->id = idr_index;
obj->type = obj_type;
if (obj_free_cb) {
obj->free_cb = obj_free_cb;
@@ -53,7 +56,7 @@ int __drm_mode_object_add(struct drm_device *dev, struct drm_mode_object *obj,
}
mutex_unlock(&dev->mode_config.idr_mutex);
- return ret < 0 ? ret : 0;
+ return ret;
}
/**
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 789ba0b..f7a0742 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -134,6 +134,7 @@ static int drm_syncobj_create(struct drm_file *file_private,
u32 *handle)
{
int ret;
+ unsigned long idr_index;
struct drm_syncobj *syncobj;
syncobj = kzalloc(sizeof(struct drm_syncobj), GFP_KERNEL);
@@ -144,17 +145,18 @@ static int drm_syncobj_create(struct drm_file *file_private,
idr_preload(GFP_KERNEL);
spin_lock(&file_private->syncobj_table_lock);
- ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);
+ ret = idr_alloc(&file_private->syncobj_idr, syncobj, &idr_index,
+ 1, 0, GFP_NOWAIT);
spin_unlock(&file_private->syncobj_table_lock);
idr_preload_end();
- if (ret < 0) {
+ if (ret) {
drm_syncobj_put(syncobj);
return ret;
}
- *handle = ret;
+ *handle = idr_index;
return 0;
}
@@ -253,6 +255,7 @@ static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
int fd, u32 *handle)
{
struct drm_syncobj *syncobj = drm_syncobj_fdget(fd);
+ unsigned long idr_index;
int ret;
if (!syncobj)
@@ -263,15 +266,16 @@ static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
idr_preload(GFP_KERNEL);
spin_lock(&file_private->syncobj_table_lock);
- ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);
+ ret = idr_alloc(&file_private->syncobj_idr, syncobj, &idr_index,
+ 1, 0, GFP_NOWAIT);
spin_unlock(&file_private->syncobj_table_lock);
idr_preload_end();
- if (ret < 0) {
+ if (ret) {
fput(syncobj->file);
return ret;
}
- *handle = ret;
+ *handle = idr_index;
return 0;
}
@@ -344,7 +348,7 @@ int drm_syncobj_export_sync_file(struct drm_file *file_private,
}
static int
-drm_syncobj_release_handle(int id, void *ptr, void *data)
+drm_syncobj_release_handle(unsigned long id, void *ptr, void *data)
{
struct drm_syncobj *syncobj = ptr;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
index 3edda18..93c69af 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
@@ -117,12 +117,13 @@ int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv)
return 0;
}
-static int ipp_create_id(struct idr *id_idr, struct mutex *lock, void *obj)
+static int ipp_create_id(struct idr *id_idr, struct mutex *lock, void *obj,
+ unsigned long *id)
{
int ret;
mutex_lock(lock);
- ret = idr_alloc(id_idr, obj, 1, 0, GFP_KERNEL);
+ ret = idr_alloc(id_idr, obj, id, 1, 0, GFP_KERNEL);
mutex_unlock(lock);
return ret;
@@ -326,6 +327,7 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
struct drm_exynos_ipp_property *property = data;
struct exynos_drm_ippdrv *ippdrv;
struct drm_exynos_ipp_cmd_node *c_node;
+ unsigned long idr_index;
u32 prop_id;
int ret, i;
@@ -381,12 +383,13 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
if (!c_node)
return -ENOMEM;
- ret = ipp_create_id(&ctx->prop_idr, &ctx->prop_lock, c_node);
- if (ret < 0) {
+ ret = ipp_create_id(&ctx->prop_idr, &ctx->prop_lock, c_node,
+ &idr_index);
+ if (ret) {
DRM_ERROR("failed to create id.\n");
goto err_clear;
}
- property->prop_id = ret;
+ property->prop_id = idr_index;
DRM_DEBUG_KMS("created prop_id[%d]cmd[%d]ippdrv[%pK]\n",
property->prop_id, property->cmd, ippdrv);
@@ -1588,21 +1591,23 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
{
struct ipp_context *ctx = get_ipp_context(dev);
struct exynos_drm_ippdrv *ippdrv;
+ unsigned long idr_index;
int ret, count = 0;
/* get ipp driver entry */
list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
ippdrv->drm_dev = drm_dev;
- ret = ipp_create_id(&ctx->ipp_idr, &ctx->ipp_lock, ippdrv);
- if (ret < 0) {
+ ret = ipp_create_id(&ctx->ipp_idr, &ctx->ipp_lock, ippdrv,
+ &idr_index);
+ if (ret) {
DRM_ERROR("failed to create id.\n");
goto err;
}
- ippdrv->prop_list.ipp_id = ret;
+ ippdrv->prop_list.ipp_id = idr_index;
- DRM_DEBUG_KMS("count[%d]ippdrv[%pK]ipp_id[%d]\n",
- count++, ippdrv, ret);
+ DRM_DEBUG_KMS("count[%d]ippdrv[%pK]ipp_id[%ld]\n",
+ count++, ippdrv, idr_index);
/* store parent device for node */
ippdrv->parent_dev = dev;
diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c
index 7cb0818..ce04352 100644
--- a/drivers/gpu/drm/i915/gvt/display.c
+++ b/drivers/gpu/drm/i915/gvt/display.c
@@ -394,7 +394,7 @@ static void emulate_vblank(struct intel_vgpu *vgpu)
void intel_gvt_emulate_vblank(struct intel_gvt *gvt)
{
struct intel_vgpu *vgpu;
- int id;
+ unsigned long id;
if (WARN_ON(!mutex_is_locked(&gvt->lock)))
return;
diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c
index fd0c85f..fb5c87f 100644
--- a/drivers/gpu/drm/i915/gvt/kvmgt.c
+++ b/drivers/gpu/drm/i915/gvt/kvmgt.c
@@ -1323,7 +1323,7 @@ static bool __kvmgt_vgpu_exist(struct intel_vgpu *vgpu, struct kvm *kvm)
{
struct intel_vgpu *itr;
struct kvmgt_guest_info *info;
- int id;
+ unsigned long id;
bool ret = false;
mutex_lock(&vgpu->gvt->lock);
diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c
index 90c14e6..719b80c 100644
--- a/drivers/gpu/drm/i915/gvt/vgpu.c
+++ b/drivers/gpu/drm/i915/gvt/vgpu.c
@@ -324,6 +324,7 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt,
struct intel_vgpu_creation_params *param)
{
struct intel_vgpu *vgpu;
+ unsigned long idr_index;
int ret;
gvt_dbg_core("handle %llu low %llu MB high %llu MB fence %llu\n",
@@ -336,12 +337,12 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt,
mutex_lock(&gvt->lock);
- ret = idr_alloc(&gvt->vgpu_idr, vgpu, IDLE_VGPU_IDR + 1, GVT_MAX_VGPU,
- GFP_KERNEL);
- if (ret < 0)
+ ret = idr_alloc(&gvt->vgpu_idr, vgpu, &idr_index, IDLE_VGPU_IDR + 1,
+ GVT_MAX_VGPU, GFP_KERNEL);
+ if (ret)
goto out_free_vgpu;
- vgpu->id = ret;
+ vgpu->id = idr_index;
vgpu->handle = param->handle;
vgpu->gvt = gvt;
vgpu->sched_ctl.weight = param->weight;
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 00d8967..0818eac 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -286,7 +286,7 @@ struct file_stats {
u64 active, inactive;
};
-static int per_file_stats(int id, void *ptr, void *data)
+static int per_file_stats(unsigned long id, void *ptr, void *data)
{
struct drm_i915_gem_object *obj = ptr;
struct file_stats *stats = data;
@@ -359,7 +359,7 @@ static void print_batch_pool_stats(struct seq_file *m,
print_file_stats(m, "[k]batch pool", stats);
}
-static int per_file_ctx_stats(int id, void *ptr, void *data)
+static int per_file_ctx_stats(unsigned long id, void *ptr, void *data)
{
struct i915_gem_context *ctx = ptr;
int n;
@@ -2156,7 +2156,7 @@ static int i915_swizzle_info(struct seq_file *m, void *data)
return 0;
}
-static int per_file_ctx(int id, void *ptr, void *data)
+static int per_file_ctx(unsigned long id, void *ptr, void *data)
{
struct i915_gem_context *ctx = ptr;
struct seq_file *m = data;
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 39ed58a..7d601b2 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -252,6 +252,7 @@ static u32 default_desc_template(const struct drm_i915_private *i915,
struct drm_i915_file_private *file_priv)
{
struct i915_gem_context *ctx;
+ unsigned long idr_index;
int ret;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -283,12 +284,12 @@ static u32 default_desc_template(const struct drm_i915_private *i915,
/* Default context will never have a file_priv */
ret = DEFAULT_CONTEXT_HANDLE;
if (file_priv) {
- ret = idr_alloc(&file_priv->context_idr, ctx,
+ ret = idr_alloc(&file_priv->context_idr, ctx, &idr_index,
DEFAULT_CONTEXT_HANDLE, 0, GFP_KERNEL);
- if (ret < 0)
+ if (ret)
goto err_lut;
}
- ctx->user_handle = ret;
+ ctx->user_handle = idr_index;
ctx->file_priv = file_priv;
if (file_priv) {
@@ -517,7 +518,7 @@ void i915_gem_context_fini(struct drm_i915_private *dev_priv)
ida_destroy(&dev_priv->context_hw_ida);
}
-static int context_idr_cleanup(int id, void *p, void *data)
+static int context_idr_cleanup(unsigned long id, void *p, void *data)
{
struct i915_gem_context *ctx = p;
diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c
index 74fc936..81cff18 100644
--- a/drivers/gpu/drm/qxl/qxl_cmd.c
+++ b/drivers/gpu/drm/qxl/qxl_cmd.c
@@ -445,18 +445,18 @@ void qxl_io_monitors_config(struct qxl_device *qdev)
int qxl_surface_id_alloc(struct qxl_device *qdev,
struct qxl_bo *surf)
{
- uint32_t handle;
+ unsigned long handle;
int idr_ret;
int count = 0;
again:
idr_preload(GFP_ATOMIC);
spin_lock(&qdev->surf_id_idr_lock);
- idr_ret = idr_alloc(&qdev->surf_id_idr, NULL, 1, 0, GFP_NOWAIT);
+ idr_ret = idr_alloc(&qdev->surf_id_idr, NULL, &handle, 1, 0,
+ GFP_NOWAIT);
spin_unlock(&qdev->surf_id_idr_lock);
idr_preload_end();
- if (idr_ret < 0)
+ if (idr_ret)
return idr_ret;
- handle = idr_ret;
if (handle >= qdev->rom->n_surfaces) {
count++;
diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c
index e6ec845..c7b2047 100644
--- a/drivers/gpu/drm/qxl/qxl_release.c
+++ b/drivers/gpu/drm/qxl/qxl_release.c
@@ -128,8 +128,9 @@ static long qxl_fence_wait(struct dma_fence *fence, bool intr,
struct qxl_release **ret)
{
struct qxl_release *release;
- int handle;
size_t size = sizeof(*release);
+ unsigned long handle;
+ int idr_ret;
release = kmalloc(size, GFP_KERNEL);
if (!release) {
@@ -144,19 +145,20 @@ static long qxl_fence_wait(struct dma_fence *fence, bool intr,
idr_preload(GFP_KERNEL);
spin_lock(&qdev->release_idr_lock);
- handle = idr_alloc(&qdev->release_idr, release, 1, 0, GFP_NOWAIT);
+ idr_ret = idr_alloc(&qdev->release_idr, release, &handle, 1, 0,
+ GFP_NOWAIT);
release->base.seqno = ++qdev->release_seqno;
spin_unlock(&qdev->release_idr_lock);
idr_preload_end();
- if (handle < 0) {
+ if (idr_ret) {
kfree(release);
*ret = NULL;
- return handle;
+ return idr_ret;
}
*ret = release;
- QXL_INFO(qdev, "allocated release %d\n", handle);
+ QXL_INFO(qdev, "allocated release %lu\n", handle);
release->id = handle;
- return handle;
+ return idr_ret;
}
static void
diff --git a/drivers/gpu/drm/sis/sis_mm.c b/drivers/gpu/drm/sis/sis_mm.c
index 1622db2..f69a49e 100644
--- a/drivers/gpu/drm/sis/sis_mm.c
+++ b/drivers/gpu/drm/sis/sis_mm.c
@@ -88,6 +88,7 @@ static int sis_drm_alloc(struct drm_device *dev, struct drm_file *file,
struct sis_memblock *item;
struct sis_file_private *file_priv = file->driver_priv;
unsigned long offset;
+ unsigned long idr_index;
mutex_lock(&dev->struct_mutex);
@@ -128,10 +129,11 @@ static int sis_drm_alloc(struct drm_device *dev, struct drm_file *file,
if (retval)
goto fail_alloc;
- retval = idr_alloc(&dev_priv->object_idr, item, 1, 0, GFP_KERNEL);
- if (retval < 0)
+ retval = idr_alloc(&dev_priv->object_idr, item, &idr_index, 1, 0,
+ GFP_KERNEL);
+ if (retval)
goto fail_idr;
- user_key = retval;
+ user_key = idr_index;
list_add(&item->owner_list, &file_priv->obj_list);
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 518f4b6..290e994 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -644,20 +644,22 @@ static int tegra_client_open(struct tegra_drm_file *fpriv,
struct tegra_drm_client *client,
struct tegra_drm_context *context)
{
+ unsigned long idr_index;
int err;
err = client->ops->open_channel(client, context);
if (err < 0)
return err;
- err = idr_alloc(&fpriv->contexts, context, 1, 0, GFP_KERNEL);
- if (err < 0) {
+ err = idr_alloc(&fpriv->contexts, context, &idr_index, 1, 0,
+ GFP_KERNEL);
+ if (err) {
client->ops->close_channel(context);
return err;
}
context->client = client;
- context->id = err;
+ context->id = idr_index;
return 0;
}
@@ -982,7 +984,7 @@ static int tegra_gem_get_flags(struct drm_device *drm, void *data,
.llseek = noop_llseek,
};
-static int tegra_drm_context_cleanup(int id, void *p, void *data)
+static int tegra_drm_context_cleanup(unsigned long id, void *p, void *data)
{
struct tegra_drm_context *context = p;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c b/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c
index 623a914..66a4c1a 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c
@@ -204,6 +204,7 @@ static void __init tilcdc_convert_slave_node(void)
/* For all memory needed for the overlay tree. This memory can
be freed after the overlay has been applied. */
struct kfree_table kft;
+ unsigned long id;
int ret;
if (kfree_table_init(&kft))
@@ -247,7 +248,7 @@ static void __init tilcdc_convert_slave_node(void)
tilcdc_node_disable(slave);
- ret = of_overlay_create(overlay);
+ ret = of_overlay_create(overlay, &id);
if (ret)
pr_err("%s: Creating overlay failed: %d\n", __func__, ret);
else
diff --git a/drivers/gpu/drm/vgem/vgem_fence.c b/drivers/gpu/drm/vgem/vgem_fence.c
index 3109c83..2558118 100644
--- a/drivers/gpu/drm/vgem/vgem_fence.c
+++ b/drivers/gpu/drm/vgem/vgem_fence.c
@@ -158,6 +158,7 @@ int vgem_fence_attach_ioctl(struct drm_device *dev,
struct reservation_object *resv;
struct drm_gem_object *obj;
struct dma_fence *fence;
+ unsigned long idr_index;
int ret;
if (arg->flags & ~VGEM_FENCE_WRITE)
@@ -200,12 +201,11 @@ int vgem_fence_attach_ioctl(struct drm_device *dev,
/* Record the fence in our idr for later signaling */
if (ret == 0) {
mutex_lock(&vfile->fence_mutex);
- ret = idr_alloc(&vfile->fence_idr, fence, 1, 0, GFP_KERNEL);
+ ret = idr_alloc(&vfile->fence_idr, fence, &idr_index, 1, 0,
+ GFP_KERNEL);
mutex_unlock(&vfile->fence_mutex);
- if (ret > 0) {
- arg->out_fence = ret;
- ret = 0;
- }
+ if (ret == 0)
+ arg->out_fence = idr_index;
}
err_fence:
if (ret) {
@@ -269,7 +269,7 @@ int vgem_fence_open(struct vgem_file *vfile)
return 0;
}
-static int __vgem_fence_idr_fini(int id, void *p, void *data)
+static int __vgem_fence_idr_fini(unsigned long id, void *p, void *data)
{
dma_fence_signal(p);
dma_fence_put(p);
diff --git a/drivers/gpu/drm/via/via_mm.c b/drivers/gpu/drm/via/via_mm.c
index 4217d66..4b848b3 100644
--- a/drivers/gpu/drm/via/via_mm.c
+++ b/drivers/gpu/drm/via/via_mm.c
@@ -116,6 +116,7 @@ int via_mem_alloc(struct drm_device *dev, void *data,
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
struct via_file_private *file_priv = file->driver_priv;
unsigned long tmpSize;
+ unsigned long idr_index;
if (mem->type > VIA_MEM_AGP) {
DRM_ERROR("Unknown memory type allocation\n");
@@ -148,10 +149,11 @@ int via_mem_alloc(struct drm_device *dev, void *data,
if (retval)
goto fail_alloc;
- retval = idr_alloc(&dev_priv->object_idr, item, 1, 0, GFP_KERNEL);
- if (retval < 0)
+ retval = idr_alloc(&dev_priv->object_idr, item, &idr_index, 1, 0,
+ GFP_KERNEL);
+ if (retval)
goto fail_idr;
- user_key = retval;
+ user_key = idr_index;
list_add(&item->owner_list, &file_priv->obj_list);
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c
index 6400506..2a251c2 100644
--- a/drivers/gpu/drm/virtio/virtgpu_kms.c
+++ b/drivers/gpu/drm/virtio/virtgpu_kms.c
@@ -55,11 +55,12 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work)
static void virtio_gpu_ctx_id_get(struct virtio_gpu_device *vgdev,
uint32_t *resid)
{
- int handle;
+ int ret;
+ unsigned long handle;
idr_preload(GFP_KERNEL);
spin_lock(&vgdev->ctx_id_idr_lock);
- handle = idr_alloc(&vgdev->ctx_id_idr, NULL, 1, 0, 0);
+ ret = idr_alloc(&vgdev->ctx_id_idr, NULL, &handle, 1, 0, 0);
spin_unlock(&vgdev->ctx_id_idr_lock);
idr_preload_end();
*resid = handle;
diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
index 9eb96fb2..6d08d42 100644
--- a/drivers/gpu/drm/virtio/virtgpu_vq.c
+++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
@@ -41,11 +41,12 @@
void virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
uint32_t *resid)
{
- int handle;
+ int ret;
+ unsigned long handle;
idr_preload(GFP_KERNEL);
spin_lock(&vgdev->resource_idr_lock);
- handle = idr_alloc(&vgdev->resource_idr, NULL, 1, 0, GFP_NOWAIT);
+ ret = idr_alloc(&vgdev->resource_idr, NULL, &handle, 1, 0, GFP_NOWAIT);
spin_unlock(&vgdev->resource_idr_lock);
idr_preload_end();
*resid = handle;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index a96f90f..5bade53 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -160,19 +160,20 @@ int vmw_resource_alloc_id(struct vmw_resource *res)
struct vmw_private *dev_priv = res->dev_priv;
int ret;
struct idr *idr = &dev_priv->res_idr[res->func->res_type];
+ unsigned long idr_index;
BUG_ON(res->id != -1);
idr_preload(GFP_KERNEL);
write_lock(&dev_priv->resource_lock);
- ret = idr_alloc(idr, res, 1, 0, GFP_NOWAIT);
- if (ret >= 0)
- res->id = ret;
+ ret = idr_alloc(idr, res, &idr_index, 1, 0, GFP_NOWAIT);
+ if (ret == 0)
+ res->id = idr_index;
write_unlock(&dev_priv->resource_lock);
idr_preload_end();
- return ret < 0 ? ret : 0;
+ return ret;
}
/**
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 12822a4..c867083 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -1306,13 +1306,15 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
*/
static int __i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
- int id;
+ unsigned long idr_index;
+ int ret;
mutex_lock(&core_lock);
- id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1, GFP_KERNEL);
+ ret = idr_alloc(&i2c_adapter_idr, adap, &idr_index,
+ adap->nr, adap->nr + 1, GFP_KERNEL);
mutex_unlock(&core_lock);
- if (WARN(id < 0, "couldn't get idr"))
- return id == -ENOSPC ? -EBUSY : id;
+ if (WARN(ret, "couldn't get idr"))
+ return ret == -ENOSPC ? -EBUSY : ret;
return i2c_register_adapter(adap);
}
@@ -1334,7 +1336,8 @@ static int __i2c_add_numbered_adapter(struct i2c_adapter *adap)
int i2c_add_adapter(struct i2c_adapter *adapter)
{
struct device *dev = &adapter->dev;
- int id;
+ unsigned long id;
+ int ret;
if (dev->of_node) {
id = of_alias_get_id(dev->of_node, "i2c");
@@ -1345,11 +1348,11 @@ int i2c_add_adapter(struct i2c_adapter *adapter)
}
mutex_lock(&core_lock);
- id = idr_alloc(&i2c_adapter_idr, adapter,
+ ret = idr_alloc(&i2c_adapter_idr, adapter, &id,
__i2c_first_dynamic_bus_num, 0, GFP_KERNEL);
mutex_unlock(&core_lock);
- if (WARN(id < 0, "couldn't get idr"))
- return id;
+ if (WARN(ret, "couldn't get idr"))
+ return ret;
adapter->nr = id;
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 2b4d613..4e7642c 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -493,18 +493,20 @@ static int cm_init_av_by_path(struct sa_path_rec *path, struct cm_av *av,
static int cm_alloc_id(struct cm_id_private *cm_id_priv)
{
unsigned long flags;
- int id;
+ unsigned long id;
+ int ret;
idr_preload(GFP_KERNEL);
spin_lock_irqsave(&cm.lock, flags);
- id = idr_alloc_cyclic(&cm.local_id_table, cm_id_priv, 0, 0, GFP_NOWAIT);
+ ret = idr_alloc_cyclic(&cm.local_id_table, cm_id_priv, &id, 0, 0,
+ GFP_NOWAIT);
spin_unlock_irqrestore(&cm.lock, flags);
idr_preload_end();
cm_id_priv->id.local_id = (__force __be32)id ^ cm.random_id_operand;
- return id < 0 ? id : 0;
+ return ret;
}
static void cm_free_id(__be32 local_id)
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 0eb3932..258476d 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -216,11 +216,12 @@ struct class_port_info_context {
};
static int cma_ps_alloc(struct net *net, enum rdma_port_space ps,
- struct rdma_bind_list *bind_list, int snum)
+ struct rdma_bind_list *bind_list, int snum,
+ unsigned long *port)
{
struct idr *idr = cma_pernet_idr(net, ps);
- return idr_alloc(idr, bind_list, snum, snum + 1, GFP_KERNEL);
+ return idr_alloc(idr, bind_list, port, snum, snum + 1, GFP_KERNEL);
}
static struct rdma_bind_list *cma_ps_find(struct net *net,
@@ -2977,6 +2978,7 @@ static int cma_alloc_port(enum rdma_port_space ps,
struct rdma_id_private *id_priv, unsigned short snum)
{
struct rdma_bind_list *bind_list;
+ unsigned long port;
int ret;
bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
@@ -2984,12 +2986,12 @@ static int cma_alloc_port(enum rdma_port_space ps,
return -ENOMEM;
ret = cma_ps_alloc(id_priv->id.route.addr.dev_addr.net, ps, bind_list,
- snum);
- if (ret < 0)
+ snum, &port);
+ if (ret)
goto err;
bind_list->ps = ps;
- bind_list->port = (unsigned short)ret;
+ bind_list->port = (unsigned short)port;
cma_bind_port(bind_list, id_priv);
return 0;
err:
diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c
index 41c31a2..63c06b9 100644
--- a/drivers/infiniband/core/rdma_core.c
+++ b/drivers/infiniband/core/rdma_core.c
@@ -102,6 +102,7 @@ static struct ib_uobject *alloc_uobj(struct ib_ucontext *context,
static int idr_add_uobj(struct ib_uobject *uobj)
{
+ unsigned long idr_index;
int ret;
idr_preload(GFP_KERNEL);
@@ -112,15 +113,15 @@ static int idr_add_uobj(struct ib_uobject *uobj)
* object which isn't initialized yet. We'll replace it later on with
* the real object once we commit.
*/
- ret = idr_alloc(&uobj->context->ufile->idr, NULL, 0,
+ ret = idr_alloc(&uobj->context->ufile->idr, NULL, &idr_index, 0,
min_t(unsigned long, U32_MAX - 1, INT_MAX), GFP_NOWAIT);
- if (ret >= 0)
- uobj->id = ret;
+ if (ret == 0)
+ uobj->id = idr_index;
spin_unlock(&uobj->context->ufile->idr_lock);
idr_preload_end();
- return ret < 0 ? ret : 0;
+ return ret;
}
/*
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 70fa4ca..6b3d469 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -1400,19 +1400,20 @@ static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask)
{
bool preload = gfpflags_allow_blocking(gfp_mask);
unsigned long flags;
- int ret, id;
+ unsigned long id;
+ int ret;
if (preload)
idr_preload(gfp_mask);
spin_lock_irqsave(&idr_lock, flags);
- id = idr_alloc(&query_idr, query, 0, 0, GFP_NOWAIT);
+ ret = idr_alloc(&query_idr, query, &id, 0, 0, GFP_NOWAIT);
spin_unlock_irqrestore(&idr_lock, flags);
if (preload)
idr_preload_end();
- if (id < 0)
- return id;
+ if (ret)
+ return ret;
query->mad_buf->timeout_ms = timeout_ms;
query->mad_buf->context[0] = query;
@@ -1422,7 +1423,7 @@ static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask)
(!(query->flags & IB_SA_QUERY_OPA))) {
if (!ibnl_chk_listeners(RDMA_NL_GROUP_LS)) {
if (!ib_nl_make_request(query, gfp_mask))
- return id;
+ return ret;
}
ib_sa_disable_local_svc(query);
}
@@ -1439,7 +1440,7 @@ static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask)
* send may already have completed and freed the query in
* another context.
*/
- return ret ? ret : id;
+ return ret;
}
void ib_sa_unpack_path(void *attribute, struct sa_path_rec *rec)
@@ -1672,7 +1673,7 @@ int ib_sa_path_rec_get(struct ib_sa_client *client,
query->conv_pr : rec;
ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
- if (ret < 0)
+ if (ret)
goto err3;
return ret;
@@ -1796,7 +1797,7 @@ int ib_sa_service_rec_query(struct ib_sa_client *client,
*sa_query = &query->sa_query;
ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
- if (ret < 0)
+ if (ret)
goto err2;
return ret;
@@ -1888,7 +1889,7 @@ int ib_sa_mcmember_rec_query(struct ib_sa_client *client,
*sa_query = &query->sa_query;
ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
- if (ret < 0)
+ if (ret)
goto err2;
return ret;
@@ -1986,7 +1987,7 @@ int ib_sa_guid_info_rec_query(struct ib_sa_client *client,
*sa_query = &query->sa_query;
ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
- if (ret < 0)
+ if (ret)
goto err2;
return ret;
@@ -2136,7 +2137,7 @@ static int ib_sa_classport_info_rec_query(struct ib_sa_port *port,
*sa_query = &query->sa_query;
ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
- if (ret < 0)
+ if (ret)
goto err_free_mad;
return ret;
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
index 112099c..5b2dd07 100644
--- a/drivers/infiniband/core/ucm.c
+++ b/drivers/infiniband/core/ucm.c
@@ -177,6 +177,8 @@ static void ib_ucm_cleanup_events(struct ib_ucm_context *ctx)
static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file)
{
struct ib_ucm_context *ctx;
+ unsigned long idr_index;
+ int ret;
ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
if (!ctx)
@@ -188,11 +190,12 @@ static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file)
INIT_LIST_HEAD(&ctx->events);
mutex_lock(&ctx_id_mutex);
- ctx->id = idr_alloc(&ctx_id_table, ctx, 0, 0, GFP_KERNEL);
+ ret = idr_alloc(&ctx_id_table, ctx, &idr_index, 0, 0, GFP_KERNEL);
mutex_unlock(&ctx_id_mutex);
- if (ctx->id < 0)
+ if (ret)
goto error;
+ ctx->id = idr_index;
list_add_tail(&ctx->file_list, &file->ctxs);
return ctx;
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 276f0ef..c66b34fd 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -184,6 +184,8 @@ static void ucma_close_id(struct work_struct *work)
static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file)
{
struct ucma_context *ctx;
+ unsigned long idr_index;
+ int ret;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -196,11 +198,12 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file)
ctx->file = file;
mutex_lock(&mut);
- ctx->id = idr_alloc(&ctx_idr, ctx, 0, 0, GFP_KERNEL);
+ ret = idr_alloc(&ctx_idr, ctx, &idr_index, 0, 0, GFP_KERNEL);
mutex_unlock(&mut);
- if (ctx->id < 0)
+ if (ret)
goto error;
+ ctx->id = idr_index;
list_add_tail(&ctx->list, &file->ctx_list);
return ctx;
@@ -212,17 +215,20 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file)
static struct ucma_multicast* ucma_alloc_multicast(struct ucma_context *ctx)
{
struct ucma_multicast *mc;
+ unsigned long idr_index;
+ int ret;
mc = kzalloc(sizeof(*mc), GFP_KERNEL);
if (!mc)
return NULL;
mutex_lock(&mut);
- mc->id = idr_alloc(&multicast_idr, mc, 0, 0, GFP_KERNEL);
+ ret = idr_alloc(&multicast_idr, mc, &idr_index, 0, 0, GFP_KERNEL);
mutex_unlock(&mut);
- if (mc->id < 0)
+ if (ret)
goto error;
+ mc->id = idr_index;
mc->ctx = ctx;
list_add_tail(&mc->list, &ctx->mc_list);
return mc;
diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c
index 47b2ce2..039e3b1 100644
--- a/drivers/infiniband/hw/cxgb3/iwch.c
+++ b/drivers/infiniband/hw/cxgb3/iwch.c
@@ -63,7 +63,7 @@ struct cxgb3_client t3c_client = {
static LIST_HEAD(dev_list);
static DEFINE_MUTEX(dev_mutex);
-static int disable_qp_db(int id, void *p, void *data)
+static int disable_qp_db(unsigned long id, void *p, void *data)
{
struct iwch_qp *qhp = p;
@@ -71,7 +71,7 @@ static int disable_qp_db(int id, void *p, void *data)
return 0;
}
-static int enable_qp_db(int id, void *p, void *data)
+static int enable_qp_db(unsigned long id, void *p, void *data)
{
struct iwch_qp *qhp = p;
diff --git a/drivers/infiniband/hw/cxgb3/iwch.h b/drivers/infiniband/hw/cxgb3/iwch.h
index 8378622..06efb1d 100644
--- a/drivers/infiniband/hw/cxgb3/iwch.h
+++ b/drivers/infiniband/hw/cxgb3/iwch.h
@@ -157,13 +157,13 @@ static inline int insert_handle(struct iwch_dev *rhp, struct idr *idr,
idr_preload(GFP_KERNEL);
spin_lock_irq(&rhp->lock);
- ret = idr_alloc(idr, handle, id, id + 1, GFP_NOWAIT);
+ ret = idr_alloc(idr, handle, NULL, id, id + 1, GFP_NOWAIT);
spin_unlock_irq(&rhp->lock);
idr_preload_end();
BUG_ON(ret == -ENOSPC);
- return ret < 0 ? ret : 0;
+ return ret;
}
static inline void remove_handle(struct iwch_dev *rhp, struct idr *idr, u32 id)
diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c
index ae0b79a..d1bd4cd 100644
--- a/drivers/infiniband/hw/cxgb4/device.c
+++ b/drivers/infiniband/hw/cxgb4/device.c
@@ -87,7 +87,7 @@ struct c4iw_debugfs_data {
int pos;
};
-static int count_idrs(int id, void *p, void *data)
+static int count_idrs(unsigned long id, void *p, void *data)
{
int *countp = data;
@@ -260,7 +260,7 @@ static void set_ep_sin6_addrs(struct c4iw_ep *ep,
}
}
-static int dump_qp(int id, void *p, void *data)
+static int dump_qp(unsigned long id, void *p, void *data)
{
struct c4iw_qp *qp = p;
struct c4iw_debugfs_data *qpd = data;
@@ -382,7 +382,7 @@ static int qp_open(struct inode *inode, struct file *file)
.llseek = default_llseek,
};
-static int dump_stag(int id, void *p, void *data)
+static int dump_stag(unsigned long id, void *p, void *data)
{
struct c4iw_debugfs_data *stagd = data;
int space;
@@ -562,7 +562,7 @@ static ssize_t stats_clear(struct file *file, const char __user *buf,
.write = stats_clear,
};
-static int dump_ep(int id, void *p, void *data)
+static int dump_ep(unsigned long id, void *p, void *data)
{
struct c4iw_ep *ep = p;
struct c4iw_debugfs_data *epd = data;
@@ -621,7 +621,7 @@ static int dump_ep(int id, void *p, void *data)
return 0;
}
-static int dump_listen_ep(int id, void *p, void *data)
+static int dump_listen_ep(unsigned long id, void *p, void *data)
{
struct c4iw_listen_ep *ep = p;
struct c4iw_debugfs_data *epd = data;
@@ -1254,7 +1254,7 @@ static int c4iw_uld_state_change(void *handle, enum cxgb4_state new_state)
return 0;
}
-static int disable_qp_db(int id, void *p, void *data)
+static int disable_qp_db(unsigned long id, void *p, void *data)
{
struct c4iw_qp *qp = p;
@@ -1276,7 +1276,7 @@ static void stop_queues(struct uld_ctx *ctx)
spin_unlock_irqrestore(&ctx->dev->lock, flags);
}
-static int enable_qp_db(int id, void *p, void *data)
+static int enable_qp_db(unsigned long id, void *p, void *data)
{
struct c4iw_qp *qp = p;
@@ -1356,7 +1356,7 @@ struct qp_list {
struct c4iw_qp **qps;
};
-static int add_and_ref_qp(int id, void *p, void *data)
+static int add_and_ref_qp(unsigned long id, void *p, void *data)
{
struct qp_list *qp_listp = data;
struct c4iw_qp *qp = p;
@@ -1366,7 +1366,7 @@ static int add_and_ref_qp(int id, void *p, void *data)
return 0;
}
-static int count_qps(int id, void *p, void *data)
+static int count_qps(unsigned long id, void *p, void *data)
{
unsigned *countp = data;
(*countp)++;
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index 819a306..2e65b95 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -303,7 +303,7 @@ static inline int _insert_handle(struct c4iw_dev *rhp, struct idr *idr,
spin_lock_irq(&rhp->lock);
}
- ret = idr_alloc(idr, handle, id, id + 1, GFP_ATOMIC);
+ ret = idr_alloc(idr, handle, NULL, id, id + 1, GFP_ATOMIC);
if (lock) {
spin_unlock_irq(&rhp->lock);
@@ -311,7 +311,7 @@ static inline int _insert_handle(struct c4iw_dev *rhp, struct idr *idr,
}
BUG_ON(ret == -ENOSPC);
- return ret < 0 ? ret : 0;
+ return ret;
}
static inline int insert_handle(struct c4iw_dev *rhp, struct idr *idr,
diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c
index 4a11d4d..30c97b2 100644
--- a/drivers/infiniband/hw/hfi1/init.c
+++ b/drivers/infiniband/hw/hfi1/init.c
@@ -1042,6 +1042,7 @@ struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, size_t extra)
unsigned long flags;
struct hfi1_devdata *dd;
int ret, nports;
+ unsigned long idr_index;
/* extra is * number of ports */
nports = extra / sizeof(struct hfi1_pportdata);
@@ -1057,16 +1058,16 @@ struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, size_t extra)
idr_preload(GFP_KERNEL);
spin_lock_irqsave(&hfi1_devs_lock, flags);
- ret = idr_alloc(&hfi1_unit_table, dd, 0, 0, GFP_NOWAIT);
- if (ret >= 0) {
- dd->unit = ret;
+ ret = idr_alloc(&hfi1_unit_table, dd, &idr_index, 0, 0, GFP_NOWAIT);
+ if (ret == 0) {
+ dd->unit = idr_index;
list_add(&dd->list, &hfi1_dev_list);
}
spin_unlock_irqrestore(&hfi1_devs_lock, flags);
idr_preload_end();
- if (ret < 0) {
+ if (ret) {
hfi1_early_err(&pdev->dev,
"Could not allocate unit ID: error %d\n", -ret);
goto bail;
diff --git a/drivers/infiniband/hw/hfi1/vnic_main.c b/drivers/infiniband/hw/hfi1/vnic_main.c
index 339f0cd..3b4addc 100644
--- a/drivers/infiniband/hw/hfi1/vnic_main.c
+++ b/drivers/infiniband/hw/hfi1/vnic_main.c
@@ -593,7 +593,7 @@ void hfi1_vnic_bypass_rcv(struct hfi1_packet *packet)
*/
if (unlikely(!vinfo)) {
struct hfi1_vnic_vport_info *vinfo_tmp;
- int id_tmp = 0;
+ unsigned long id_tmp = 0;
vinfo_tmp = idr_get_next(&dd->vnic.vesw_idr, &id_tmp);
if (vinfo_tmp) {
@@ -649,9 +649,9 @@ static int hfi1_vnic_up(struct hfi1_vnic_vport_info *vinfo)
if (!vinfo->vesw_id)
return -EINVAL;
- rc = idr_alloc(&dd->vnic.vesw_idr, vinfo, vinfo->vesw_id,
+ rc = idr_alloc(&dd->vnic.vesw_idr, vinfo, NULL, vinfo->vesw_id,
vinfo->vesw_id + 1, GFP_NOWAIT);
- if (rc < 0)
+ if (rc)
return rc;
for (i = 0; i < vinfo->num_rx_q; i++) {
diff --git a/drivers/infiniband/hw/mlx4/cm.c b/drivers/infiniband/hw/mlx4/cm.c
index fedaf82..c99e5c8 100644
--- a/drivers/infiniband/hw/mlx4/cm.c
+++ b/drivers/infiniband/hw/mlx4/cm.c
@@ -245,6 +245,7 @@ static void sl_id_map_add(struct ib_device *ibdev, struct id_map_entry *new)
int ret;
struct id_map_entry *ent;
struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov;
+ unsigned long idr_index;
ent = kmalloc(sizeof (struct id_map_entry), GFP_KERNEL);
if (!ent)
@@ -259,9 +260,10 @@ static void sl_id_map_add(struct ib_device *ibdev, struct id_map_entry *new)
idr_preload(GFP_KERNEL);
spin_lock(&to_mdev(ibdev)->sriov.id_map_lock);
- ret = idr_alloc_cyclic(&sriov->pv_id_table, ent, 0, 0, GFP_NOWAIT);
- if (ret >= 0) {
- ent->pv_cm_id = (u32)ret;
+ ret = idr_alloc_cyclic(&sriov->pv_id_table, ent, &idr_index, 0, 0,
+ GFP_NOWAIT);
+ if (ret == 0) {
+ ent->pv_cm_id = (u32)idr_index;
sl_id_map_add(ibdev, ent);
list_add_tail(&ent->list, &sriov->cm_list);
}
@@ -269,12 +271,13 @@ static void sl_id_map_add(struct ib_device *ibdev, struct id_map_entry *new)
spin_unlock(&sriov->id_map_lock);
idr_preload_end();
- if (ret >= 0)
+ if (ret == 0)
return ent;
/*error flow*/
kfree(ent);
- mlx4_ib_warn(ibdev, "No more space in the idr (err:0x%x)\n", ret);
+ mlx4_ib_warn(ibdev, "No more space in the idr (err:0x%lx)\n",
+ idr_index);
return ERR_PTR(-ENOMEM);
}
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
index 57c9a2a..5224c99 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -302,6 +302,8 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
int status = 0, i;
u8 lstate = 0;
struct ocrdma_dev *dev;
+ unsigned long idr_index;
+ int ret;
dev = (struct ocrdma_dev *)ib_alloc_device(sizeof(struct ocrdma_dev));
if (!dev) {
@@ -313,9 +315,10 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
goto idr_err;
memcpy(&dev->nic_info, dev_info, sizeof(*dev_info));
- dev->id = idr_alloc(&ocrdma_dev_id, NULL, 0, 0, GFP_KERNEL);
- if (dev->id < 0)
+ ret = idr_alloc(&ocrdma_dev_id, NULL, &idr_index, 0, 0, GFP_KERNEL);
+ if (ret)
goto idr_err;
+ dev->id = idr_index;
status = ocrdma_init_hw(dev);
if (status)
diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c
index 6c16ba1..3bbe99f 100644
--- a/drivers/infiniband/hw/qib/qib_init.c
+++ b/drivers/infiniband/hw/qib/qib_init.c
@@ -1099,6 +1099,7 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra)
unsigned long flags;
struct qib_devdata *dd;
int ret, nports;
+ unsigned long idr_index;
/* extra is * number of ports */
nports = extra / sizeof(struct qib_pportdata);
@@ -1112,16 +1113,16 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra)
idr_preload(GFP_KERNEL);
spin_lock_irqsave(&qib_devs_lock, flags);
- ret = idr_alloc(&qib_unit_table, dd, 0, 0, GFP_NOWAIT);
- if (ret >= 0) {
- dd->unit = ret;
+ ret = idr_alloc(&qib_unit_table, dd, &idr_index, 0, 0, GFP_NOWAIT);
+ if (ret == 0) {
+ dd->unit = idr_index;
list_add(&dd->list, &qib_dev_list);
}
spin_unlock_irqrestore(&qib_devs_lock, flags);
idr_preload_end();
- if (ret < 0) {
+ if (ret) {
qib_early_err(&pdev->dev,
"Could not allocate unit ID: error %d\n", -ret);
goto bail;
diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c
index cf768dd..b220e91 100644
--- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c
+++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c
@@ -204,9 +204,9 @@ static struct opa_vnic_adapter *vema_add_vport(struct opa_vnic_vema_port *port,
int rc;
adapter->cport = cport;
- rc = idr_alloc(&port->vport_idr, adapter, vport_num,
+ rc = idr_alloc(&port->vport_idr, adapter, NULL, vport_num,
vport_num + 1, GFP_NOWAIT);
- if (rc < 0) {
+ if (rc) {
opa_vnic_rem_netdev(adapter);
adapter = ERR_PTR(rc);
}
@@ -850,7 +850,7 @@ void opa_vnic_vema_send_trap(struct opa_vnic_adapter *adapter,
v_err("Aborting trap\n");
}
-static int vema_rem_vport(int id, void *p, void *data)
+static int vema_rem_vport(unsigned long id, void *p, void *data)
{
struct opa_vnic_adapter *adapter = p;
@@ -858,7 +858,7 @@ static int vema_rem_vport(int id, void *p, void *data)
return 0;
}
-static int vema_enable_vport(int id, void *p, void *data)
+static int vema_enable_vport(unsigned long id, void *p, void *data)
{
struct opa_vnic_adapter *adapter = p;
@@ -866,7 +866,7 @@ static int vema_enable_vport(int id, void *p, void *data)
return 0;
}
-static int vema_disable_vport(int id, void *p, void *data)
+static int vema_disable_vport(unsigned long id, void *p, void *data)
{
struct opa_vnic_adapter *adapter = p;
diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c
index f167c0d..bf30a25 100644
--- a/drivers/iommu/intel-svm.c
+++ b/drivers/iommu/intel-svm.c
@@ -299,6 +299,7 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_
struct mm_struct *mm = NULL;
int pasid_max;
int ret;
+ unsigned long idr_index;
if (WARN_ON(!iommu))
return -EINVAL;
@@ -320,7 +321,7 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_
mutex_lock(&pasid_mutex);
if (pasid && !(flags & SVM_FLAG_PRIVATE_PASID)) {
- int i;
+ unsigned long i;
idr_for_each_entry(&iommu->pasid_idr, svm, i) {
if (svm->mm != mm ||
@@ -382,14 +383,14 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_
pasid_max = iommu->pasid_max;
/* Do not use PASID 0 in caching mode (virtualised IOMMU) */
- ret = idr_alloc(&iommu->pasid_idr, svm,
+ ret = idr_alloc(&iommu->pasid_idr, svm, &idr_index,
!!cap_caching_mode(iommu->cap),
pasid_max - 1, GFP_KERNEL);
- if (ret < 0) {
+ if (ret) {
kfree(svm);
goto out;
}
- svm->pasid = ret;
+ svm->pasid = idr_index;
svm->notifier.ops = &intel_mmuops;
svm->mm = mm;
svm->flags = flags;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 2edbcc2..974884c 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1607,11 +1607,12 @@ static int specific_minor(int minor)
idr_preload(GFP_KERNEL);
spin_lock(&_minor_lock);
- r = idr_alloc(&_minor_idr, MINOR_ALLOCED, minor, minor + 1, GFP_NOWAIT);
+ r = idr_alloc(&_minor_idr, MINOR_ALLOCED, NULL, minor, minor + 1,
+ GFP_NOWAIT);
spin_unlock(&_minor_lock);
idr_preload_end();
- if (r < 0)
+ if (r)
return r == -ENOSPC ? -EBUSY : r;
return 0;
}
@@ -1619,17 +1620,19 @@ static int specific_minor(int minor)
static int next_free_minor(int *minor)
{
int r;
+ unsigned long idr_index;
idr_preload(GFP_KERNEL);
spin_lock(&_minor_lock);
- r = idr_alloc(&_minor_idr, MINOR_ALLOCED, 0, 1 << MINORBITS, GFP_NOWAIT);
+ r = idr_alloc(&_minor_idr, MINOR_ALLOCED, &idr_index,
+ 0, 1 << MINORBITS, GFP_NOWAIT);
spin_unlock(&_minor_lock);
idr_preload_end();
- if (r < 0)
+ if (r)
return r;
- *minor = r;
+ *minor = idr_index;
return 0;
}
diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index 76382c8..266ef03 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -511,17 +511,19 @@ struct memstick_host *memstick_alloc_host(unsigned int extra,
int memstick_add_host(struct memstick_host *host)
{
int rc;
+ unsigned long idr_index;
idr_preload(GFP_KERNEL);
spin_lock(&memstick_host_lock);
- rc = idr_alloc(&memstick_host_idr, host, 0, 0, GFP_NOWAIT);
- if (rc >= 0)
- host->id = rc;
+ rc = idr_alloc(&memstick_host_idr, host, &idr_index, 0, 0,
+ GFP_NOWAIT);
+ if (rc == 0)
+ host->id = idr_index;
spin_unlock(&memstick_host_lock);
idr_preload_end();
- if (rc < 0)
+ if (rc)
return rc;
dev_set_name(&host->dev, "memstick%u", host->id);
diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c
index 22de7f5..b1f33f2 100644
--- a/drivers/memstick/core/ms_block.c
+++ b/drivers/memstick/core/ms_block.c
@@ -2099,16 +2099,19 @@ static int msb_init_disk(struct memstick_dev *card)
int rc;
u64 limit = BLK_BOUNCE_HIGH;
unsigned long capacity;
+ unsigned long idr_index;
if (host->dev.dma_mask && *(host->dev.dma_mask))
limit = *(host->dev.dma_mask);
mutex_lock(&msb_disk_lock);
- msb->disk_id = idr_alloc(&msb_disk_idr, card, 0, 256, GFP_KERNEL);
+ rc = idr_alloc(&msb_disk_idr, card, &idr_index, 0, 256, GFP_KERNEL);
mutex_unlock(&msb_disk_lock);
- if (msb->disk_id < 0)
- return msb->disk_id;
+ if (rc)
+ return rc;
+
+ msb->disk_id = idr_index;
msb->disk = alloc_disk(0);
if (!msb->disk) {
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index 8897962..51204ae 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -1177,6 +1177,8 @@ static int mspro_block_init_disk(struct memstick_dev *card)
int rc, disk_id;
u64 limit = BLK_BOUNCE_HIGH;
unsigned long capacity;
+ unsigned long idr_index;
+ int ret;
if (host->dev.dma_mask && *(host->dev.dma_mask))
limit = *(host->dev.dma_mask);
@@ -1200,10 +1202,14 @@ static int mspro_block_init_disk(struct memstick_dev *card)
msb->page_size = be16_to_cpu(sys_info->unit_size);
mutex_lock(&mspro_block_disk_lock);
- disk_id = idr_alloc(&mspro_block_disk_idr, card, 0, 256, GFP_KERNEL);
+ ret = idr_alloc(&mspro_block_disk_idr, card, &idr_index, 0, 256,
+ GFP_KERNEL);
mutex_unlock(&mspro_block_disk_lock);
- if (disk_id < 0)
- return disk_id;
+
+ if (ret)
+ return ret;
+
+ disk_id = idr_index;
msb->disk = alloc_disk(1 << MSPRO_BLOCK_PART_SHIFT);
if (!msb->disk) {
diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c
index a0ac89d..ef44cf0 100644
--- a/drivers/mfd/rtsx_pcr.c
+++ b/drivers/mfd/rtsx_pcr.c
@@ -1172,6 +1172,7 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
struct pcr_handle *handle;
u32 base, len;
int ret, i, bar = 0;
+ unsigned long idr_index;
dev_dbg(&(pcidev->dev),
": Realtek PCI-E Card Reader found at %s [%04x:%04x] (rev %x)\n",
@@ -1205,12 +1206,12 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
idr_preload(GFP_KERNEL);
spin_lock(&rtsx_pci_lock);
- ret = idr_alloc(&rtsx_pci_idr, pcr, 0, 0, GFP_NOWAIT);
- if (ret >= 0)
- pcr->id = ret;
+ ret = idr_alloc(&rtsx_pci_idr, pcr, &idr_index, 0, 0, GFP_NOWAIT);
+ if (ret == 0)
+ pcr->id = idr_index;
spin_unlock(&rtsx_pci_lock);
idr_preload_end();
- if (ret < 0)
+ if (ret)
goto free_handle;
pcr->pci = pcidev;
diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c
index 1922cb8..f21cd35 100644
--- a/drivers/misc/c2port/core.c
+++ b/drivers/misc/c2port/core.c
@@ -896,6 +896,7 @@ struct c2port_device *c2port_device_register(char *name,
struct c2port_ops *ops, void *devdata)
{
struct c2port_device *c2dev;
+ unsigned long idr_index;
int ret;
if (unlikely(!ops) || unlikely(!ops->access) || \
@@ -910,13 +911,13 @@ struct c2port_device *c2port_device_register(char *name,
idr_preload(GFP_KERNEL);
spin_lock_irq(&c2port_idr_lock);
- ret = idr_alloc(&c2port_idr, c2dev, 0, 0, GFP_NOWAIT);
+ ret = idr_alloc(&c2port_idr, c2dev, &idr_index, 0, 0, GFP_NOWAIT);
spin_unlock_irq(&c2port_idr_lock);
idr_preload_end();
- if (ret < 0)
+ if (ret)
goto error_idr_alloc;
- c2dev->id = ret;
+ c2dev->id = idr_index;
bin_attr_flash_data.size = ops->blocks_num * ops->block_size;
diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c
index 8c32040..cf32e3b 100644
--- a/drivers/misc/cxl/context.c
+++ b/drivers/misc/cxl/context.c
@@ -38,6 +38,7 @@ struct cxl_context *cxl_context_alloc(void)
int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master)
{
int i;
+ unsigned long idr_index;
ctx->afu = afu;
ctx->master = master;
@@ -93,14 +94,15 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master)
*/
mutex_lock(&afu->contexts_lock);
idr_preload(GFP_KERNEL);
- i = idr_alloc(&ctx->afu->contexts_idr, ctx, ctx->afu->adapter->min_pe,
+ i = idr_alloc(&ctx->afu->contexts_idr, ctx, &idr_index,
+ ctx->afu->adapter->min_pe,
ctx->afu->num_procs, GFP_NOWAIT);
idr_preload_end();
mutex_unlock(&afu->contexts_lock);
- if (i < 0)
+ if (i)
return i;
- ctx->pe = i;
+ ctx->pe = idr_index;
if (cpu_has_feature(CPU_FTR_HVMODE)) {
ctx->elem = &ctx->afu->native->spa[i];
ctx->external_pe = ctx->pe;
diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c
index c1ba0d4..cb2f9a9 100644
--- a/drivers/misc/cxl/main.c
+++ b/drivers/misc/cxl/main.c
@@ -80,7 +80,8 @@ static inline void cxl_slbia_core(struct mm_struct *mm)
struct cxl *adapter;
struct cxl_afu *afu;
struct cxl_context *ctx;
- int card, slice, id;
+ int slice;
+ unsigned long card, id;
pr_devel("%s called\n", __func__);
@@ -202,17 +203,19 @@ struct cxl *get_cxl_adapter(int num)
static int cxl_alloc_adapter_nr(struct cxl *adapter)
{
- int i;
+ int ret;
+ unsigned long idr_index;
idr_preload(GFP_KERNEL);
spin_lock(&adapter_idr_lock);
- i = idr_alloc(&cxl_adapter_idr, adapter, 0, 0, GFP_NOWAIT);
+ ret = idr_alloc(&cxl_adapter_idr, adapter, &idr_index, 0, 0,
+ GFP_NOWAIT);
spin_unlock(&adapter_idr_lock);
idr_preload_end();
- if (i < 0)
- return i;
+ if (ret)
+ return ret;
- adapter->adapter_num = i;
+ adapter->adapter_num = idr_index;
return 0;
}
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index e825f01..7c8c39f 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -792,11 +792,13 @@ static ssize_t hbm_ver_drv_show(struct device *device,
static int mei_minor_get(struct mei_device *dev)
{
int ret;
+ unsigned long idr_index;
mutex_lock(&mei_minor_lock);
- ret = idr_alloc(&mei_idr, dev, 0, MEI_MAX_DEVS, GFP_KERNEL);
- if (ret >= 0)
- dev->minor = ret;
+ ret = idr_alloc(&mei_idr, dev, &idr_index, 0, MEI_MAX_DEVS,
+ GFP_KERNEL);
+ if (ret == 0)
+ dev->minor = idr_index;
else if (ret == -ENOSPC)
dev_err(dev->dev, "too many mei devices\n");
diff --git a/drivers/misc/mic/scif/scif_api.c b/drivers/misc/mic/scif/scif_api.c
index ddc9e4b..d07cb6c 100644
--- a/drivers/misc/mic/scif/scif_api.c
+++ b/drivers/misc/mic/scif/scif_api.c
@@ -336,6 +336,7 @@ int __scif_flush(scif_epd_t epd)
int scif_bind(scif_epd_t epd, u16 pn)
{
struct scif_endpt *ep = (struct scif_endpt *)epd;
+ unsigned long port;
int ret = 0;
int tmp;
@@ -364,14 +365,14 @@ int scif_bind(scif_epd_t epd, u16 pn)
}
if (pn) {
- tmp = scif_rsrv_port(pn);
- if (tmp != pn) {
+ tmp = scif_rsrv_port(pn, &port);
+ if (port != pn) {
ret = -EINVAL;
goto scif_bind_exit;
}
} else {
- pn = scif_get_new_port();
- if (!pn) {
+ pn = scif_get_new_port(&port);
+ if (pn < 0) {
ret = -ENOSPC;
goto scif_bind_exit;
}
@@ -379,7 +380,7 @@ int scif_bind(scif_epd_t epd, u16 pn)
ep->state = SCIFEP_BOUND;
ep->port.node = scif_info.nodeid;
- ep->port.port = pn;
+ ep->port.port = port;
ep->conn_async_state = ASYNC_CONN_IDLE;
ret = pn;
dev_dbg(scif_info.mdev.this_device,
diff --git a/drivers/misc/mic/scif/scif_ports.c b/drivers/misc/mic/scif/scif_ports.c
index 594e18d..8a1938f 100644
--- a/drivers/misc/mic/scif/scif_ports.c
+++ b/drivers/misc/mic/scif/scif_ports.c
@@ -41,19 +41,19 @@ struct scif_port {
* @return : Allocated SCIF port #, or -ENOSPC if port unavailable.
* On memory allocation failure, returns -ENOMEM.
*/
-static int __scif_get_port(int start, int end)
+static int __scif_get_port(unsigned long index, int start, int end)
{
- int id;
+ int ret;
struct scif_port *port = kzalloc(sizeof(*port), GFP_ATOMIC);
if (!port)
return -ENOMEM;
spin_lock(&scif_info.port_lock);
- id = idr_alloc(&scif_ports, port, start, end, GFP_ATOMIC);
- if (id >= 0)
+ ret = idr_alloc(&scif_ports, port, &index, start, end, GFP_ATOMIC);
+ if (ret == 0)
port->ref_cnt++;
spin_unlock(&scif_info.port_lock);
- return id;
+ return ret;
}
/**
@@ -63,9 +63,9 @@ static int __scif_get_port(int start, int end)
* @return : Allocated SCIF port #, or -ENOSPC if port unavailable.
* On memory allocation failure, returns -ENOMEM.
*/
-int scif_rsrv_port(u16 port)
+int scif_rsrv_port(u16 port, unsigned long *index)
{
- return __scif_get_port(port, port + 1);
+ return __scif_get_port(index, port, port + 1);
}
/**
@@ -75,9 +75,9 @@ int scif_rsrv_port(u16 port)
* @return : Allocated SCIF port #, or -ENOSPC if no ports available.
* On memory allocation failure, returns -ENOMEM.
*/
-int scif_get_new_port(void)
+int scif_get_new_port(unsigned long *index)
{
- return __scif_get_port(SCIF_PORT_RSVD + 1, SCIF_PORT_COUNT);
+ return __scif_get_port(index, SCIF_PORT_RSVD + 1, SCIF_PORT_COUNT);
}
/**
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index a511b2a..d4b0777 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -197,15 +197,16 @@ struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
int tifm_add_adapter(struct tifm_adapter *fm)
{
int rc;
+ unsigned long idr_index;
idr_preload(GFP_KERNEL);
spin_lock(&tifm_adapter_lock);
- rc = idr_alloc(&tifm_adapter_idr, fm, 0, 0, GFP_NOWAIT);
- if (rc >= 0)
- fm->id = rc;
+ rc = idr_alloc(&tifm_adapter_idr, fm, &idr_index, 0, 0, GFP_NOWAIT);
+ if (rc == 0)
+ fm->id = idr_index;
spin_unlock(&tifm_adapter_lock);
idr_preload_end();
- if (rc < 0)
+ if (rc)
return rc;
dev_set_name(&fm->dev, "tifm%u", fm->id);
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 956382c..da2d6a4 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -85,7 +85,7 @@ static int mtd_cls_resume(struct device *dev)
DEFINE_MUTEX(mtd_table_mutex);
EXPORT_SYMBOL_GPL(mtd_table_mutex);
-struct mtd_info *__mtd_next_device(int i)
+struct mtd_info *__mtd_next_device(unsigned long i)
{
return idr_get_next(&mtd_idr, &i);
}
@@ -489,6 +489,7 @@ int mtd_pairing_groups(struct mtd_info *mtd)
int add_mtd_device(struct mtd_info *mtd)
{
struct mtd_notifier *not;
+ unsigned long idr_index;
int i, error;
/*
@@ -502,13 +503,13 @@ int add_mtd_device(struct mtd_info *mtd)
BUG_ON(mtd->writesize == 0);
mutex_lock(&mtd_table_mutex);
- i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
- if (i < 0) {
+ i = idr_alloc(&mtd_idr, mtd, &idr_index, 0, 0, GFP_KERNEL);
+ if (i) {
error = i;
goto fail_locked;
}
- mtd->index = i;
+ mtd->index = idr_index;
mtd->usecount = 0;
/* default value if not set by driver */
diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h
index 55fdb8e..28c5674 100644
--- a/drivers/mtd/mtdcore.h
+++ b/drivers/mtd/mtdcore.h
@@ -5,7 +5,7 @@
extern struct mutex mtd_table_mutex;
-struct mtd_info *__mtd_next_device(int i);
+struct mtd_info *__mtd_next_device(unsigned long i);
int add_mtd_device(struct mtd_info *mtd);
int del_mtd_device(struct mtd_info *mtd);
int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index c3963f8..96be456 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -358,6 +358,7 @@ int ubiblock_create(struct ubi_volume_info *vi)
struct ubiblock *dev;
struct gendisk *gd;
u64 disk_capacity = vi->used_bytes >> 9;
+ unsigned long idr_index;
int ret;
if ((sector_t)disk_capacity != disk_capacity)
@@ -390,13 +391,15 @@ int ubiblock_create(struct ubi_volume_info *vi)
gd->fops = &ubiblock_ops;
gd->major = ubiblock_major;
- gd->first_minor = idr_alloc(&ubiblock_minor_idr, dev, 0, 0, GFP_KERNEL);
- if (gd->first_minor < 0) {
+ ret = idr_alloc(&ubiblock_minor_idr, dev, &idr_index,
+ 0, 0, GFP_KERNEL);
+ if (ret) {
dev_err(disk_to_dev(gd),
"block: dynamic minor allocation failed");
ret = -ENODEV;
goto out_put_disk;
}
+ gd->first_minor = idr_index;
gd->private_data = dev;
sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id);
set_capacity(gd, disk_capacity);
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index a404552..b982238 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -286,7 +286,7 @@ static void ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb,
static int ppp_connect_channel(struct channel *pch, int unit);
static int ppp_disconnect_channel(struct channel *pch);
static void ppp_destroy_channel(struct channel *pch);
-static int unit_get(struct idr *p, void *ptr);
+static int unit_get(struct idr *p, void *ptr, unsigned long *index);
static int unit_set(struct idr *p, void *ptr, int n);
static void unit_put(struct idr *p, int n);
static void *unit_find(struct idr *p, int n);
@@ -943,7 +943,7 @@ static __net_exit void ppp_exit_net(struct net *net)
struct net_device *aux;
struct ppp *ppp;
LIST_HEAD(list);
- int id;
+ unsigned long id;
rtnl_lock();
for_each_netdev_safe(net, dev, aux) {
@@ -972,13 +972,14 @@ static __net_exit void ppp_exit_net(struct net *net)
static int ppp_unit_register(struct ppp *ppp, int unit, bool ifname_is_set)
{
struct ppp_net *pn = ppp_pernet(ppp->ppp_net);
+ unsigned long idr_index;
int ret;
mutex_lock(&pn->all_ppp_mutex);
if (unit < 0) {
- ret = unit_get(&pn->units_idr, ppp);
- if (ret < 0)
+ ret = unit_get(&pn->units_idr, ppp, &idr_index);
+ if (ret)
goto err;
} else {
/* Caller asked for a specific unit number. Fail with -EEXIST
@@ -991,13 +992,13 @@ static int ppp_unit_register(struct ppp *ppp, int unit, bool ifname_is_set)
goto err;
}
ret = unit_set(&pn->units_idr, ppp, unit);
- if (ret < 0) {
+ if (ret) {
/* Rewrite error for backward compatibility */
ret = -EEXIST;
goto err;
}
}
- ppp->file.index = ret;
+ ppp->file.index = idr_index;
if (!ifname_is_set)
snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ppp->file.index);
@@ -3222,18 +3223,18 @@ static void __exit ppp_cleanup(void)
/* associate pointer with specified number */
static int unit_set(struct idr *p, void *ptr, int n)
{
- int unit;
+ int ret;
- unit = idr_alloc(p, ptr, n, n + 1, GFP_KERNEL);
- if (unit == -ENOSPC)
- unit = -EINVAL;
- return unit;
+ ret = idr_alloc(p, ptr, NULL, n, n + 1, GFP_KERNEL);
+ if (ret == -ENOSPC)
+ ret = -EINVAL;
+ return ret;
}
/* get new free unit number and associate pointer with it */
-static int unit_get(struct idr *p, void *ptr)
+static int unit_get(struct idr *p, void *ptr, unsigned long *index)
{
- return idr_alloc(p, ptr, 0, 0, GFP_KERNEL);
+ return idr_alloc(p, ptr, index, 0, 0, GFP_KERNEL);
}
/* put unit number back to a pool */
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index 0d03941..7b306ab 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -408,6 +408,7 @@ int tap_get_minor(dev_t major, struct tap_dev *tap)
{
int retval = -ENOMEM;
struct major_info *tap_major;
+ unsigned long idr_index;
rcu_read_lock();
tap_major = tap_get_major(MAJOR(major));
@@ -417,9 +418,10 @@ int tap_get_minor(dev_t major, struct tap_dev *tap)
}
spin_lock(&tap_major->minor_lock);
- retval = idr_alloc(&tap_major->minor_idr, tap, 1, TAP_NUM_DEVS, GFP_ATOMIC);
- if (retval >= 0) {
- tap->minor = retval;
+ retval = idr_alloc(&tap_major->minor_idr, tap, &idr_index,
+ 1, TAP_NUM_DEVS, GFP_ATOMIC);
+ if (retval == 0) {
+ tap->minor = idr_index;
} else if (retval == -ENOSPC) {
netdev_err(tap->dev, "Too many tap devices\n");
retval = -EINVAL;
@@ -428,7 +430,7 @@ int tap_get_minor(dev_t major, struct tap_dev *tap)
unlock:
rcu_read_unlock();
- return retval < 0 ? retval : 0;
+ return retval;
}
EXPORT_SYMBOL_GPL(tap_get_minor);
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 6305308..dddb9ed 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -1826,7 +1826,8 @@ void ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw,
int ath10k_htt_tx_mgmt_inc_pending(struct ath10k_htt *htt, bool is_mgmt,
bool is_presp);
-int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb);
+int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb,
+ unsigned long *index);
void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id);
int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu);
int ath10k_htt_tx(struct ath10k_htt *htt,
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 685faac..ab7e458 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -203,14 +203,15 @@ void ath10k_htt_tx_mgmt_dec_pending(struct ath10k_htt *htt)
htt->num_pending_mgmt_tx--;
}
-int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb)
+int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb,
+ unsigned long *index)
{
struct ath10k *ar = htt->ar;
int ret;
lockdep_assert_held(&htt->tx_lock);
- ret = idr_alloc(&htt->pending_tx, skb, 0,
+ ret = idr_alloc(&htt->pending_tx, skb, index, 0,
htt->max_num_pending_tx, GFP_ATOMIC);
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", ret);
@@ -423,7 +424,8 @@ int ath10k_htt_tx_start(struct ath10k_htt *htt)
return ret;
}
-static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx)
+static int ath10k_htt_tx_clean_up_pending(unsigned long msdu_id, void *skb,
+ void *ctx)
{
struct ath10k *ar = ctx;
struct ath10k_htt *htt = &ar->htt;
@@ -832,17 +834,18 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
int msdu_id = -1;
int res;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
+ unsigned long idr_index;
len += sizeof(cmd->hdr);
len += sizeof(cmd->mgmt_tx);
spin_lock_bh(&htt->tx_lock);
- res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
+ res = ath10k_htt_tx_alloc_msdu_id(htt, msdu, &idr_index);
spin_unlock_bh(&htt->tx_lock);
- if (res < 0)
+ if (res)
goto err;
- msdu_id = res;
+ msdu_id = idr_index;
if ((ieee80211_is_action(hdr->frame_control) ||
ieee80211_is_deauth(hdr->frame_control) ||
@@ -917,14 +920,15 @@ int ath10k_htt_tx(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
u32 frags_paddr = 0;
u32 txbuf_paddr;
struct htt_msdu_ext_desc *ext_desc = NULL;
+ unsigned long idr_index;
spin_lock_bh(&htt->tx_lock);
- res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
+ res = ath10k_htt_tx_alloc_msdu_id(htt, msdu, &idr_index);
spin_unlock_bh(&htt->tx_lock);
- if (res < 0)
+ if (res)
goto err;
- msdu_id = res;
+ msdu_id = idr_index;
prefetch_len = min(htt->prefetch_len, msdu->len);
prefetch_len = roundup(prefetch_len, 4);
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 55c808f..9d70725 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3828,7 +3828,7 @@ static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq)
struct ath10k_txq *artxq;
struct ath10k_skb_cb *cb;
struct sk_buff *msdu;
- int msdu_id;
+ unsigned long msdu_id;
if (!txq)
return;
diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
index d67d700..f5151dd 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -820,23 +820,24 @@ struct sk_buff *
{
struct sk_buff *orig_skb = skb;
struct mwifiex_txinfo *tx_info, *orig_tx_info;
+ unsigned long idr_index;
skb = skb_clone(skb, GFP_ATOMIC);
if (skb) {
unsigned long flags;
- int id;
+ int ret;
spin_lock_irqsave(&priv->ack_status_lock, flags);
- id = idr_alloc(&priv->ack_status_frames, orig_skb,
- 1, 0x10, GFP_ATOMIC);
+ ret = idr_alloc(&priv->ack_status_frames, orig_skb, &idr_index,
+ 1, 0x10, GFP_ATOMIC);
spin_unlock_irqrestore(&priv->ack_status_lock, flags);
- if (id >= 0) {
+ if (ret == 0) {
tx_info = MWIFIEX_SKB_TXCB(skb);
- tx_info->ack_frame_id = id;
+ tx_info->ack_frame_id = idr_index;
tx_info->flags |= flag;
orig_tx_info = MWIFIEX_SKB_TXCB(orig_skb);
- orig_tx_info->ack_frame_id = id;
+ orig_tx_info->ack_frame_id = idr_index;
orig_tx_info->flags |= flag;
if (flag == MWIFIEX_BUF_FLAG_ACTION_TX_STATUS && cookie)
diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c
index 0edd268..d4ad66b 100644
--- a/drivers/net/wireless/marvell/mwifiex/wmm.c
+++ b/drivers/net/wireless/marvell/mwifiex/wmm.c
@@ -562,7 +562,7 @@ static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv)
}
}
-static int mwifiex_free_ack_frame(int id, void *p, void *data)
+static int mwifiex_free_ack_frame(unsigned long id, void *p, void *data)
{
pr_warn("Have pending ack frames!\n");
kfree_skb(p);
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index c0e4ee1..e5cfe01 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -373,10 +373,11 @@ static int of_free_overlay_info(struct of_overlay *ov)
*
* Returns the id of the created overlay, or a negative error number
*/
-int of_overlay_create(struct device_node *tree)
+int of_overlay_create(struct device_node *tree, unsigned long *id)
{
struct of_overlay *ov;
- int err, id;
+ unsigned long idr_index;
+ int err;
/* allocate the overlay structure */
ov = kzalloc(sizeof(*ov), GFP_KERNEL);
@@ -390,12 +391,10 @@ int of_overlay_create(struct device_node *tree)
mutex_lock(&of_mutex);
- id = idr_alloc(&ov_idr, ov, 0, 0, GFP_KERNEL);
- if (id < 0) {
- err = id;
+ err = idr_alloc(&ov_idr, ov, &idr_index, 0, 0, GFP_KERNEL);
+ if (err)
goto err_destroy_trans;
- }
- ov->id = id;
+ ov->id = idr_index;
/* build the overlay info structures */
err = of_build_overlay_info(ov, tree);
@@ -430,7 +429,7 @@ int of_overlay_create(struct device_node *tree)
mutex_unlock(&of_mutex);
- return id;
+ return err;
err_revert_overlay:
err_abort_trans:
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 0107fc6..ac7cc76 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1242,7 +1242,8 @@ static int of_unittest_apply_overlay(int overlay_nr, int unittest_nr,
int *overlay_id)
{
struct device_node *np = NULL;
- int ret, id = -1;
+ unsigned long id = -1;
+ int ret;
np = of_find_node_by_path(overlay_path(overlay_nr));
if (np == NULL) {
@@ -1252,17 +1253,14 @@ static int of_unittest_apply_overlay(int overlay_nr, int unittest_nr,
goto out;
}
- ret = of_overlay_create(np);
- if (ret < 0) {
+ ret = of_overlay_create(np, &id);
+ if (ret) {
unittest(0, "could not create overlay from \"%s\"\n",
overlay_path(overlay_nr));
goto out;
}
- id = ret;
of_unittest_track_overlay(id);
- ret = 0;
-
out:
of_node_put(np);
@@ -1442,6 +1440,7 @@ static void of_unittest_overlay_6(void)
int ret, i, ov_id[2];
int overlay_nr = 6, unittest_nr = 6;
int before = 0, after = 1;
+ unsigned long id;
/* unittest device must be in before state */
for (i = 0; i < 2; i++) {
@@ -1466,13 +1465,13 @@ static void of_unittest_overlay_6(void)
return;
}
- ret = of_overlay_create(np);
- if (ret < 0) {
+ ret = of_overlay_create(np, &id);
+ if (ret) {
unittest(0, "could not create overlay from \"%s\"\n",
overlay_path(overlay_nr + i));
return;
}
- ov_id[i] = ret;
+ ov_id[i] = id;
of_unittest_track_overlay(ov_id[i]);
}
@@ -2094,6 +2093,7 @@ static int __init overlay_data_add(int onum)
int ret;
u32 size;
u32 size_from_header;
+ unsigned long id;
for (k = 0, info = overlays; info; info++, k++) {
if (k == onum)
@@ -2138,13 +2138,12 @@ static int __init overlay_data_add(int onum)
goto out_free_np_overlay;
}
- ret = of_overlay_create(info->np_overlay);
- if (ret < 0) {
+ ret = of_overlay_create(info->np_overlay, &id);
+ if (ret) {
pr_err("of_overlay_create() (ret=%d), %d\n", ret, onum);
goto out_free_np_overlay;
} else {
- info->overlay_id = ret;
- ret = 0;
+ info->overlay_id = id;
}
pr_debug("__dtb_overlay_begin applied, overlay id %d\n", ret);
diff --git a/drivers/power/supply/bq2415x_charger.c b/drivers/power/supply/bq2415x_charger.c
index c4770a9..268f099 100644
--- a/drivers/power/supply/bq2415x_charger.c
+++ b/drivers/power/supply/bq2415x_charger.c
@@ -1542,7 +1542,6 @@ static int bq2415x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
- int num;
char *name = NULL;
struct bq2415x_device *bq;
struct device_node *np = client->dev.of_node;
@@ -1550,6 +1549,7 @@ static int bq2415x_probe(struct i2c_client *client,
const struct acpi_device_id *acpi_id = NULL;
struct power_supply *notify_psy = NULL;
union power_supply_propval prop;
+ unsigned long idr_index;
if (!np && !pdata && !ACPI_HANDLE(&client->dev)) {
dev_err(&client->dev, "Neither devicetree, nor platform data, nor ACPI support\n");
@@ -1558,13 +1558,13 @@ static int bq2415x_probe(struct i2c_client *client,
/* Get new ID for the new device */
mutex_lock(&bq2415x_id_mutex);
- num = idr_alloc(&bq2415x_id, client, 0, 0, GFP_KERNEL);
+ ret = idr_alloc(&bq2415x_id, client, &idr_index, 0, 0, GFP_KERNEL);
mutex_unlock(&bq2415x_id_mutex);
- if (num < 0)
- return num;
+ if (ret)
+ return ret;
if (id) {
- name = kasprintf(GFP_KERNEL, "%s-%d", id->name, num);
+ name = kasprintf(GFP_KERNEL, "%s-%d", id->name, idr_index);
} else if (ACPI_HANDLE(&client->dev)) {
acpi_id =
acpi_match_device(client->dev.driver->acpi_match_table,
@@ -1574,7 +1574,7 @@ static int bq2415x_probe(struct i2c_client *client,
ret = -ENODEV;
goto error_1;
}
- name = kasprintf(GFP_KERNEL, "%s-%d", acpi_id->id, num);
+ name = kasprintf(GFP_KERNEL, "%s-%d", acpi_id->id, idr_index);
}
if (!name) {
dev_err(&client->dev, "failed to allocate device name\n");
@@ -1590,7 +1590,7 @@ static int bq2415x_probe(struct i2c_client *client,
i2c_set_clientdata(client, bq);
- bq->id = num;
+ bq->id = idr_index;
bq->dev = &client->dev;
if (id)
bq->chip = id->driver_data;
@@ -1714,7 +1714,7 @@ static int bq2415x_probe(struct i2c_client *client,
kfree(name);
error_1:
mutex_lock(&bq2415x_id_mutex);
- idr_remove(&bq2415x_id, num);
+ idr_remove(&bq2415x_id, idr_index);
mutex_unlock(&bq2415x_id_mutex);
return ret;
diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
index a597221..6517416 100644
--- a/drivers/power/supply/bq27xxx_battery_i2c.c
+++ b/drivers/power/supply/bq27xxx_battery_i2c.c
@@ -148,18 +148,19 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct bq27xxx_device_info *di;
+ unsigned long idr_index;
int ret;
char *name;
- int num;
/* Get new ID for the new battery device */
mutex_lock(&battery_mutex);
- num = idr_alloc(&battery_id, client, 0, 0, GFP_KERNEL);
+ ret = idr_alloc(&battery_id, client, &idr_index, 0, 0, GFP_KERNEL);
mutex_unlock(&battery_mutex);
- if (num < 0)
- return num;
+ if (ret)
+ return ret;
- name = devm_kasprintf(&client->dev, GFP_KERNEL, "%s-%d", id->name, num);
+ name = devm_kasprintf(&client->dev, GFP_KERNEL, "%s-%d", id->name,
+ idr_index);
if (!name)
goto err_mem;
@@ -167,7 +168,7 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
if (!di)
goto err_mem;
- di->id = num;
+ di->id = idr_index;
di->dev = &client->dev;
di->chip = id->driver_data;
di->name = name;
@@ -206,7 +207,7 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
err_failed:
mutex_lock(&battery_mutex);
- idr_remove(&battery_id, num);
+ idr_remove(&battery_id, idr_index);
mutex_unlock(&battery_mutex);
return ret;
diff --git a/drivers/power/supply/ds2782_battery.c b/drivers/power/supply/ds2782_battery.c
index a1b7e05..19bf20b 100644
--- a/drivers/power/supply/ds2782_battery.c
+++ b/drivers/power/supply/ds2782_battery.c
@@ -380,6 +380,7 @@ static int ds278x_battery_probe(struct i2c_client *client,
struct ds278x_platform_data *pdata = client->dev.platform_data;
struct power_supply_config psy_cfg = {};
struct ds278x_info *info;
+ unsigned long idr_index;
int ret;
int num;
@@ -394,11 +395,11 @@ static int ds278x_battery_probe(struct i2c_client *client,
/* Get an ID for this battery */
mutex_lock(&battery_lock);
- ret = idr_alloc(&battery_id, client, 0, 0, GFP_KERNEL);
+ ret = idr_alloc(&battery_id, client, &idr_index, 0, 0, GFP_KERNEL);
mutex_unlock(&battery_lock);
- if (ret < 0)
+ if (ret)
goto fail_id;
- num = ret;
+ num = idr_index;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
@@ -446,7 +447,7 @@ static int ds278x_battery_probe(struct i2c_client *client,
kfree(info);
fail_info:
mutex_lock(&battery_lock);
- idr_remove(&battery_id, num);
+ idr_remove(&battery_id, idr_index);
mutex_unlock(&battery_lock);
fail_id:
return ret;
diff --git a/drivers/powercap/powercap_sys.c b/drivers/powercap/powercap_sys.c
index 5b10b50..52a8493 100644
--- a/drivers/powercap/powercap_sys.c
+++ b/drivers/powercap/powercap_sys.c
@@ -502,6 +502,7 @@ struct powercap_zone *powercap_register_zone(
{
int result;
int nr_attrs;
+ unsigned long idr_index;
if (!name || !control_type || !ops ||
nr_constraints > MAX_CONSTRAINTS_PER_ZONE ||
@@ -532,11 +533,12 @@ struct powercap_zone *powercap_register_zone(
mutex_lock(&control_type->lock);
/* Using idr to get the unique id */
- result = idr_alloc(power_zone->parent_idr, NULL, 0, 0, GFP_KERNEL);
- if (result < 0)
+ result = idr_alloc(power_zone->parent_idr, NULL, &idr_index, 0, 0,
+ GFP_KERNEL);
+ if (result)
goto err_idr_alloc;
- power_zone->id = result;
+ power_zone->id = idr_index;
idr_init(&power_zone->idr);
result = -ENOMEM;
power_zone->name = kstrdup(name, GFP_KERNEL);
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
index 6eb0db3..cd167d2 100644
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -354,14 +354,16 @@ int pps_register_cdev(struct pps_device *pps)
{
int err;
dev_t devt;
+ unsigned long idr_index;
mutex_lock(&pps_idr_lock);
/*
* Get new ID for the new PPS source. After idr_alloc() calling
* the new source will be freely available into the kernel.
*/
- err = idr_alloc(&pps_idr, pps, 0, PPS_MAX_SOURCES, GFP_KERNEL);
- if (err < 0) {
+ err = idr_alloc(&pps_idr, pps, &idr_index, 0, PPS_MAX_SOURCES,
+ GFP_KERNEL);
+ if (err) {
if (err == -ENOSPC) {
pr_err("%s: too many PPS sources in the system\n",
pps->info.name);
@@ -369,7 +371,7 @@ int pps_register_cdev(struct pps_device *pps)
}
goto out_unlock;
}
- pps->id = err;
+ pps->id = idr_index;
mutex_unlock(&pps_idr_lock);
devt = MKDEV(MAJOR(pps_devt), pps->id);
@@ -437,7 +439,7 @@ void pps_unregister_cdev(struct pps_device *pps)
struct pps_device *pps_lookup_dev(void const *cookie)
{
struct pps_device *pps;
- unsigned id;
+ unsigned long id;
rcu_read_lock();
idr_for_each_entry(&pps_idr, pps, id)
diff --git a/drivers/rapidio/rio_cm.c b/drivers/rapidio/rio_cm.c
index bad0e0e..70310e9 100644
--- a/drivers/rapidio/rio_cm.c
+++ b/drivers/rapidio/rio_cm.c
@@ -1287,7 +1287,8 @@ static int riocm_ch_bind(u16 ch_id, u8 mport_id, void *context)
*/
static struct rio_channel *riocm_ch_alloc(u16 ch_num)
{
- int id;
+ int ret;
+ unsigned long id;
int start, end;
struct rio_channel *ch;
@@ -1307,13 +1308,13 @@ static struct rio_channel *riocm_ch_alloc(u16 ch_num)
idr_preload(GFP_KERNEL);
spin_lock_bh(&idr_lock);
- id = idr_alloc_cyclic(&ch_idr, ch, start, end, GFP_NOWAIT);
+ ret = idr_alloc_cyclic(&ch_idr, ch, &id, start, end, GFP_NOWAIT);
spin_unlock_bh(&idr_lock);
idr_preload_end();
- if (id < 0) {
+ if (ret) {
kfree(ch);
- return ERR_PTR(id == -ENOSPC ? -EBUSY : id);
+ return ERR_PTR(id == -ENOSPC ? -EBUSY : ret);
}
ch->id = (u16)id;
@@ -1501,7 +1502,7 @@ static int riocm_cdev_open(struct inode *inode, struct file *filp)
static int riocm_cdev_release(struct inode *inode, struct file *filp)
{
struct rio_channel *ch, *_c;
- unsigned int i;
+ unsigned long i;
LIST_HEAD(list);
riocm_debug(EXIT, "by %s(%d) filp=%p",
@@ -1998,7 +1999,7 @@ static void riocm_remove_dev(struct device *dev, struct subsys_interface *sif)
struct cm_dev *cm;
struct cm_peer *peer;
struct rio_channel *ch, *_c;
- unsigned int i;
+ unsigned long i;
bool found = false;
LIST_HEAD(list);
@@ -2179,7 +2180,7 @@ static void riocm_remove_mport(struct device *dev,
struct cm_dev *cm;
struct cm_peer *peer, *temp;
struct rio_channel *ch, *_c;
- unsigned int i;
+ unsigned long i;
bool found = false;
LIST_HEAD(list);
@@ -2241,7 +2242,7 @@ static int rio_cm_shutdown(struct notifier_block *nb, unsigned long code,
void *unused)
{
struct rio_channel *ch;
- unsigned int i;
+ unsigned long i;
LIST_HEAD(list);
riocm_debug(EXIT, ".");
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 564061d..63f2110 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -209,6 +209,7 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
dma_addr_t dma;
void *va;
int ret, size, notifyid;
+ unsigned long idr_index;
/* actual size of vring (in bytes) */
size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
@@ -228,13 +229,14 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
* TODO: assign a notifyid for rvdev updates as well
* TODO: support predefined notifyids (via resource table)
*/
- ret = idr_alloc(&rproc->notifyids, rvring, 0, 0, GFP_KERNEL);
- if (ret < 0) {
+ ret = idr_alloc(&rproc->notifyids, rvring, &idr_index, 0, 0,
+ GFP_KERNEL);
+ if (ret) {
dev_err(dev, "idr_alloc failed: %d\n", ret);
dma_free_coherent(dev->parent, size, va, dma);
return ret;
}
- notifyid = ret;
+ notifyid = idr_index;
/* Potentially bump max_notifyid */
if (notifyid > rproc->max_notifyid)
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index eee2a9f..0074aec 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -221,6 +221,7 @@ static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp,
int id_min, id_max, id;
struct rpmsg_endpoint *ept;
struct device *dev = rpdev ? &rpdev->dev : &vrp->vdev->dev;
+ unsigned long idr_index;
ept = kzalloc(sizeof(*ept), GFP_KERNEL);
if (!ept)
@@ -246,12 +247,13 @@ static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp,
mutex_lock(&vrp->endpoints_lock);
/* bind the endpoint to an rpmsg address (and allocate one if needed) */
- id = idr_alloc(&vrp->endpoints, ept, id_min, id_max, GFP_KERNEL);
- if (id < 0) {
+ id = idr_alloc(&vrp->endpoints, ept, &idr_index, id_min, id_max,
+ GFP_KERNEL);
+ if (id) {
dev_err(dev, "idr_alloc failed: %d\n", id);
goto free_ept;
}
- ept->addr = id;
+ ept->addr = idr_index;
mutex_unlock(&vrp->endpoints_lock);
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index 7eb0eef..80b4aa8 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -554,15 +554,17 @@ static void bfad_im_fc_rport_add(struct bfad_im_port_s *im_port,
struct device *dev)
{
int error = 1;
+ unsigned long idr_index;
mutex_lock(&bfad_mutex);
- error = idr_alloc(&bfad_im_port_index, im_port, 0, 0, GFP_KERNEL);
- if (error < 0) {
+ error = idr_alloc(&bfad_im_port_index, im_port, &idr_index, 0, 0,
+ GFP_KERNEL);
+ if (error) {
mutex_unlock(&bfad_mutex);
printk(KERN_WARNING "idr_alloc failure\n");
goto out;
}
- im_port->idr_id = error;
+ im_port->idr_id = idr_index;
mutex_unlock(&bfad_mutex);
im_port->shost = bfad_scsi_host_alloc(im_port, bfad);
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index dad959f..b155c9b 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -901,6 +901,7 @@ static int ch_probe(struct device *dev)
struct device *class_dev;
int ret;
scsi_changer *ch;
+ unsigned long idr_index;
if (sd->type != TYPE_MEDIUM_CHANGER)
return -ENODEV;
@@ -911,17 +912,18 @@ static int ch_probe(struct device *dev)
idr_preload(GFP_KERNEL);
spin_lock(&ch_index_lock);
- ret = idr_alloc(&ch_index_idr, ch, 0, CH_MAX_DEVS + 1, GFP_NOWAIT);
+ ret = idr_alloc(&ch_index_idr, ch, &idr_index, 0, CH_MAX_DEVS + 1,
+ GFP_NOWAIT);
spin_unlock(&ch_index_lock);
idr_preload_end();
- if (ret < 0) {
+ if (ret) {
if (ret == -ENOSPC)
ret = -ENODEV;
goto free_ch;
}
- ch->minor = ret;
+ ch->minor = idr_index;
sprintf(ch->name,"ch%d",ch->minor);
class_dev = device_create(ch_sysfs_class, dev,
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index da669dc..b0d0307 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -410,7 +410,7 @@ void *lpfc_nvmet_buf_alloc(struct lpfc_hba *phba, int flags,
int lpfc_vport_disable(struct fc_vport *fc_vport, bool disable);
int lpfc_mbx_unreg_vpi(struct lpfc_vport *);
void destroy_port(struct lpfc_vport *);
-int lpfc_get_instance(void);
+int lpfc_get_instance(unsigned long *index);
void lpfc_host_attrib_init(struct Scsi_Host *);
extern void lpfc_debugfs_initialize(struct lpfc_vport *);
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 491aa95..7e4bdad 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -3980,11 +3980,11 @@ struct lpfc_vport *
* -1 - lpfc get instance failed.
**/
int
-lpfc_get_instance(void)
+lpfc_get_instance(unsigned long *index)
{
int ret;
- ret = idr_alloc(&lpfc_hba_index, NULL, 0, 0, GFP_KERNEL);
+ ret = idr_alloc(&lpfc_hba_index, NULL, index, 0, 0, GFP_KERNEL);
return ret < 0 ? -1 : ret;
}
@@ -6756,6 +6756,8 @@ struct lpfc_rpi_hdr *
lpfc_hba_alloc(struct pci_dev *pdev)
{
struct lpfc_hba *phba;
+ unsigned long idr_index;
+ int ret;
/* Allocate memory for HBA structure */
phba = kzalloc(sizeof(struct lpfc_hba), GFP_KERNEL);
@@ -6768,8 +6770,9 @@ struct lpfc_rpi_hdr *
phba->pcidev = pdev;
/* Assign an unused board number */
- phba->brd_no = lpfc_get_instance();
- if (phba->brd_no < 0) {
+ ret = lpfc_get_instance(&idr_index);
+ phba->brd_no = idr_index;
+ if (ret) {
kfree(phba);
return NULL;
}
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index c714482..a5968bd 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -299,10 +299,11 @@ static void lpfc_discovery_wait(struct lpfc_vport *vport)
struct lpfc_vport *pport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = pport->phba;
struct lpfc_vport *vport = NULL;
- int instance;
+ int ret;
int vpi;
int rc = VPORT_ERROR;
int status;
+ unsigned long idr_index;
if ((phba->sli_rev < 3) || !(phba->cfg_enable_npiv)) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
@@ -324,7 +325,8 @@ static void lpfc_discovery_wait(struct lpfc_vport *vport)
}
/* Assign an unused board number */
- if ((instance = lpfc_get_instance()) < 0) {
+ ret = lpfc_get_instance(&idr_index);
+ if (ret) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"1810 Create VPORT failed: Cannot get "
"instance number\n");
@@ -333,7 +335,7 @@ static void lpfc_discovery_wait(struct lpfc_vport *vport)
goto error_out;
}
- vport = lpfc_create_port(phba, instance, &fc_vport->dev);
+ vport = lpfc_create_port(phba, idr_index, &fc_vport->dev);
if (!vport) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"1811 Create VPORT failed: vpi x%x\n", vpi);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index d7ff71e..82b71b7 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1402,6 +1402,7 @@ static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned lon
unsigned long iflags;
int error;
u32 k;
+ unsigned long idr_index;
sdp = kzalloc(sizeof(Sg_device), GFP_KERNEL);
if (!sdp) {
@@ -1413,8 +1414,9 @@ static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned lon
idr_preload(GFP_KERNEL);
write_lock_irqsave(&sg_index_lock, iflags);
- error = idr_alloc(&sg_index_idr, sdp, 0, SG_MAX_DEVS, GFP_NOWAIT);
- if (error < 0) {
+ error = idr_alloc(&sg_index_idr, sdp, &idr_index, 0, SG_MAX_DEVS,
+ GFP_NOWAIT);
+ if (error) {
if (error == -ENOSPC) {
sdev_printk(KERN_WARNING, scsidp,
"Unable to attach sg device type=%d, minor number exceeds %d\n",
@@ -1427,7 +1429,7 @@ static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned lon
}
goto out_unlock;
}
- k = error;
+ k = idr_index;
SCSI_LOG_TIMEOUT(3, sdev_printk(KERN_INFO, scsidp,
"sg_alloc: dev=%d \n", k));
@@ -2206,7 +2208,7 @@ static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned lon
#ifdef CONFIG_SCSI_PROC_FS
static int
-sg_idr_max_id(int id, void *p, void *data)
+sg_idr_max_id(unsigned long id, void *p, void *data)
{
int *k = data;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 8e5013d..f5a3db8 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -4261,6 +4261,7 @@ static int st_probe(struct device *dev)
struct st_buffer *buffer;
int i, error;
char *stp;
+ unsigned long idr_index;
if (SDp->type != TYPE_TAPE)
return -ENODEV;
@@ -4372,14 +4373,15 @@ static int st_probe(struct device *dev)
idr_preload(GFP_KERNEL);
spin_lock(&st_index_lock);
- error = idr_alloc(&st_index_idr, tpnt, 0, ST_MAX_TAPES + 1, GFP_NOWAIT);
+ error = idr_alloc(&st_index_idr, tpnt, &idr_index,
+ 0, ST_MAX_TAPES + 1, GFP_NOWAIT);
spin_unlock(&st_index_lock);
idr_preload_end();
- if (error < 0) {
+ if (error) {
pr_warn("st: idr allocation failed: %d\n", error);
goto out_put_queue;
}
- tpnt->index = error;
+ tpnt->index = idr_index;
sprintf(disk->disk_name, "st%d", tpnt->index);
tpnt->stats = kzalloc(sizeof(struct scsi_tape_stats), GFP_KERNEL);
if (tpnt->stats == NULL) {
diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c
index c6d01b8..1c81446 100644
--- a/drivers/staging/greybus/uart.c
+++ b/drivers/staging/greybus/uart.c
@@ -371,14 +371,16 @@ static struct gb_tty *get_gb_by_minor(unsigned int minor)
static int alloc_minor(struct gb_tty *gb_tty)
{
- int minor;
+ int ret;
+ unsigned long idr_index;
mutex_lock(&table_lock);
- minor = idr_alloc(&tty_minors, gb_tty, 0, GB_NUM_MINORS, GFP_KERNEL);
+ ret = idr_alloc(&tty_minors, gb_tty, &idr_index, 0, GB_NUM_MINORS,
+ GFP_KERNEL);
mutex_unlock(&table_lock);
- if (minor >= 0)
- gb_tty->minor = minor;
- return minor;
+ if (ret == 0)
+ gb_tty->minor = idr_index;
+ return ret;
}
static void release_minor(struct gb_tty *gb_tty)
@@ -835,7 +837,6 @@ static int gb_uart_probe(struct gbphy_device *gbphy_dev,
struct gb_tty *gb_tty;
struct device *tty_dev;
int retval;
- int minor;
gb_tty = kzalloc(sizeof(*gb_tty), GFP_KERNEL);
if (!gb_tty)
@@ -874,19 +875,16 @@ static int gb_uart_probe(struct gbphy_device *gbphy_dev,
gb_tty->credits = GB_UART_FIRMWARE_CREDITS;
init_completion(&gb_tty->credits_complete);
- minor = alloc_minor(gb_tty);
- if (minor < 0) {
- if (minor == -ENOSPC) {
+ retval = alloc_minor(gb_tty);
+ if (retval) {
+ if (ret == -ENOSPC) {
dev_err(&gbphy_dev->dev,
"no more free minor numbers\n");
retval = -ENODEV;
- } else {
- retval = minor;
}
goto exit_kfifo_free;
}
- gb_tty->minor = minor;
spin_lock_init(&gb_tty->write_lock);
spin_lock_init(&gb_tty->read_lock);
init_waitqueue_head(&gb_tty->wioctl);
diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c
index a6e7a6b..9d246f7 100644
--- a/drivers/staging/unisys/visorhba/visorhba_main.c
+++ b/drivers/staging/unisys/visorhba/visorhba_main.c
@@ -243,15 +243,16 @@ static unsigned int simple_idr_get(struct idr *idrtable, void *p,
{
int id;
unsigned long flags;
+ unsigned long idr_index;
idr_preload(GFP_KERNEL);
spin_lock_irqsave(lock, flags);
- id = idr_alloc(idrtable, p, 1, INT_MAX, GFP_NOWAIT);
+ id = idr_alloc(idrtable, p, &idr_index, 1, INT_MAX, GFP_NOWAIT);
spin_unlock_irqrestore(lock, flags);
idr_preload_end();
- if (id < 0)
+ if (id)
return 0; /* failure */
- return (unsigned int)(id); /* idr_alloc() guarantees > 0 */
+ return (unsigned int)(idr_index); /* idr_alloc() guarantees > 0 */
}
/*
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 74e4975..a43b8ba 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -120,6 +120,7 @@ void iscsit_put_tiqn_for_login(struct iscsi_tiqn *tiqn)
struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *buf)
{
struct iscsi_tiqn *tiqn = NULL;
+ unsigned long idr_index;
int ret;
if (strlen(buf) >= ISCSI_IQN_LEN) {
@@ -146,15 +147,15 @@ struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *buf)
idr_preload(GFP_KERNEL);
spin_lock(&tiqn_lock);
- ret = idr_alloc(&tiqn_idr, NULL, 0, 0, GFP_NOWAIT);
- if (ret < 0) {
+ ret = idr_alloc(&tiqn_idr, NULL, &idr_index, 0, 0, GFP_NOWAIT);
+ if (ret) {
pr_err("idr_alloc() failed for tiqn->tiqn_index\n");
spin_unlock(&tiqn_lock);
idr_preload_end();
kfree(tiqn);
return ERR_PTR(ret);
}
- tiqn->tiqn_index = ret;
+ tiqn->tiqn_index = idr_index;
list_add_tail(&tiqn->tiqn_list, &g_tiqn_list);
spin_unlock(&tiqn_lock);
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index e9bdc8b..2283ecc 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -300,6 +300,7 @@ static int iscsi_login_zero_tsih_s1(
{
struct iscsi_session *sess = NULL;
struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
+ unsigned long idr_index;
int ret;
sess = kzalloc(sizeof(struct iscsi_session), GFP_KERNEL);
@@ -335,13 +336,13 @@ static int iscsi_login_zero_tsih_s1(
idr_preload(GFP_KERNEL);
spin_lock_bh(&sess_idr_lock);
- ret = idr_alloc(&sess_idr, NULL, 0, 0, GFP_NOWAIT);
- if (ret >= 0)
- sess->session_index = ret;
+ ret = idr_alloc(&sess_idr, NULL, &idr_index, 0, 0, GFP_NOWAIT);
+ if (ret == 0)
+ sess->session_index = idr_index;
spin_unlock_bh(&sess_idr_lock);
idr_preload_end();
- if (ret < 0) {
+ if (ret) {
pr_err("idr_alloc() for sess_idr failed\n");
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
ISCSI_LOGIN_STATUS_NO_RESOURCES);
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index e8dd6da..3b18cc4 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -908,7 +908,7 @@ struct devices_idr_iter {
void *data;
};
-static int target_devices_idr_iter(int id, void *p, void *data)
+static int target_devices_idr_iter(unsigned long id, void *p, void *data)
{
struct devices_idr_iter *iter = data;
struct se_device *dev = p;
@@ -951,7 +951,8 @@ int target_for_each_device(int (*fn)(struct se_device *dev, void *data),
int target_configure_device(struct se_device *dev)
{
struct se_hba *hba = dev->se_hba;
- int ret, id;
+ unsigned long id;
+ int ret;
if (dev->dev_flags & DF_CONFIGURED) {
pr_err("se_dev->se_dev_ptr already set for storage"
@@ -968,9 +969,9 @@ int target_configure_device(struct se_device *dev)
* Use cyclic to try and avoid collisions with devices
* that were recently removed.
*/
- id = idr_alloc_cyclic(&devices_idr, dev, 0, INT_MAX, GFP_KERNEL);
+ ret = idr_alloc_cyclic(&devices_idr, dev, &id, 0, INT_MAX, GFP_KERNEL);
mutex_unlock(&device_mutex);
- if (id < 0) {
+ if (ret) {
ret = -ENOMEM;
goto out;
}
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index 80ee130..43466cc 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -430,7 +430,8 @@ static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd)
struct se_device *se_dev = se_cmd->se_dev;
struct tcmu_dev *udev = TCMU_DEV(se_dev);
struct tcmu_cmd *tcmu_cmd;
- int cmd_id;
+ unsigned long cmd_id;
+ int ret;
tcmu_cmd = kmem_cache_zalloc(tcmu_cmd_cache, GFP_KERNEL);
if (!tcmu_cmd)
@@ -453,12 +454,12 @@ static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd)
idr_preload(GFP_KERNEL);
spin_lock_irq(&udev->commands_lock);
- cmd_id = idr_alloc(&udev->commands, tcmu_cmd, 0,
- USHRT_MAX, GFP_NOWAIT);
+ ret = idr_alloc(&udev->commands, tcmu_cmd, &cmd_id, 0,
+ USHRT_MAX, GFP_NOWAIT);
spin_unlock_irq(&udev->commands_lock);
idr_preload_end();
- if (cmd_id < 0) {
+ if (ret) {
tcmu_free_cmd(tcmu_cmd);
return NULL;
}
@@ -1028,7 +1029,7 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev)
return handled;
}
-static int tcmu_check_expired_cmd(int id, void *p, void *data)
+static int tcmu_check_expired_cmd(unsigned long id, void *p, void *data)
{
struct tcmu_cmd *cmd = p;
@@ -1577,7 +1578,7 @@ static void tcmu_destroy_device(struct se_device *dev)
struct tcmu_dev *udev = TCMU_DEV(dev);
struct tcmu_cmd *cmd;
bool all_expired = true;
- int i;
+ unsigned long i;
del_timer_sync(&udev->timeout);
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
index d356d7f0..5f1e13a 100644
--- a/drivers/tee/tee_shm.c
+++ b/drivers/tee/tee_shm.c
@@ -106,6 +106,7 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
struct tee_device *teedev = ctx->teedev;
struct tee_shm_pool_mgr *poolm = NULL;
struct tee_shm *shm;
+ unsigned long idr_index;
void *ret;
int rc;
@@ -150,12 +151,13 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
}
mutex_lock(&teedev->mutex);
- shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL);
+ rc = idr_alloc(&teedev->idr, shm, &idr_index, 1, 0, GFP_KERNEL);
mutex_unlock(&teedev->mutex);
- if (shm->id < 0) {
- ret = ERR_PTR(shm->id);
+ if (rc) {
+ ret = ERR_PTR(rc);
goto err_pool_free;
}
+ shm->id = idr_index;
if (flags & TEE_SHM_DMA_BUF) {
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index ff04b7f..05a7e81 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -372,12 +372,13 @@ static void uio_dev_del_attributes(struct uio_device *idev)
static int uio_get_minor(struct uio_device *idev)
{
int retval = -ENOMEM;
+ unsigned long idr_index;
mutex_lock(&minor_lock);
- retval = idr_alloc(&uio_idr, idev, 0, UIO_MAX_DEVICES, GFP_KERNEL);
- if (retval >= 0) {
- idev->minor = retval;
- retval = 0;
+ retval = idr_alloc(&uio_idr, idev, &idr_index, 0, UIO_MAX_DEVICES,
+ GFP_KERNEL);
+ if (retval == 0) {
+ idev->minor = idr_index;
} else if (retval == -ENOSPC) {
dev_err(idev->dev, "too many uio devices\n");
retval = -EINVAL;
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 5e056064..7105336 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -97,15 +97,16 @@ static struct acm *acm_get_by_minor(unsigned int minor)
/*
* Try to find an available minor number and if found, associate it with 'acm'.
*/
-static int acm_alloc_minor(struct acm *acm)
+static int acm_alloc_minor(struct acm *acm, unsigned long *index)
{
- int minor;
+ int ret;
mutex_lock(&acm_minors_lock);
- minor = idr_alloc(&acm_minors, acm, 0, ACM_TTY_MINORS, GFP_KERNEL);
+ ret = idr_alloc(&acm_minors, acm, index, 0, ACM_TTY_MINORS,
+ GFP_KERNEL);
mutex_unlock(&acm_minors_lock);
- return minor;
+ return ret;
}
/* Release the minor number associated with 'acm'. */
@@ -1219,7 +1220,6 @@ static int acm_probe(struct usb_interface *intf,
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct usb_cdc_parsed_header h;
struct acm *acm;
- int minor;
int ctrlsize, readsize;
u8 *buf;
int call_intf_num = -1;
@@ -1231,6 +1231,7 @@ static int acm_probe(struct usb_interface *intf,
struct device *tty_dev;
int rv = -ENOMEM;
int res;
+ unsigned long idr_index;
/* normal quirks */
quirks = (unsigned long)id->driver_info;
@@ -1388,8 +1389,8 @@ static int acm_probe(struct usb_interface *intf,
if (acm == NULL)
goto alloc_fail;
- minor = acm_alloc_minor(acm);
- if (minor < 0)
+ rv = acm_alloc_minor(acm, &idr_index);
+ if (rv)
goto alloc_fail1;
ctrlsize = usb_endpoint_maxp(epctrl);
@@ -1399,7 +1400,7 @@ static int acm_probe(struct usb_interface *intf,
acm->writesize = usb_endpoint_maxp(epwrite) * 20;
acm->control = control_interface;
acm->data = data_interface;
- acm->minor = minor;
+ acm->minor = idr_index;
acm->dev = usb_dev;
if (h.usb_cdc_acm_descriptor)
acm->ctrl_caps = h.usb_cdc_acm_descriptor->bmCapabilities;
@@ -1538,7 +1539,7 @@ static int acm_probe(struct usb_interface *intf,
acm->nb_index = 0;
acm->nb_size = 0;
- dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
+ dev_info(&intf->dev, "ttyACM%ld: USB ACM device\n", idr_index);
acm->line.dwDTERate = cpu_to_le32(9600);
acm->line.bDataBits = 8;
@@ -1548,8 +1549,9 @@ static int acm_probe(struct usb_interface *intf,
usb_set_intfdata(data_interface, acm);
usb_get_intf(control_interface);
- tty_dev = tty_port_register_device(&acm->port, acm_tty_driver, minor,
- &control_interface->dev);
+ tty_dev = tty_port_register_device(&acm->port, acm_tty_driver,
+ idr_index,
+ &control_interface->dev);
if (IS_ERR(tty_dev)) {
rv = PTR_ERR(tty_dev);
goto alloc_fail8;
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index 55dea2e..bc2a969 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -605,7 +605,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf,
struct usb_bus *bus;
ssize_t ret, total_written = 0;
loff_t skip_bytes = *ppos;
- int id;
+ unsigned long id;
if (*ppos < 0)
return -EINVAL;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index ab1bb3b..43d04fb 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1017,11 +1017,12 @@ static void usb_bus_init (struct usb_bus *bus)
static int usb_register_bus(struct usb_bus *bus)
{
int result = -E2BIG;
- int busnum;
+ unsigned long busnum;
mutex_lock(&usb_bus_idr_lock);
- busnum = idr_alloc(&usb_bus_idr, bus, 1, USB_MAXBUS, GFP_KERNEL);
- if (busnum < 0) {
+ result = idr_alloc(&usb_bus_idr, bus, &busnum, 1, USB_MAXBUS,
+ GFP_KERNEL);
+ if (result) {
pr_err("%s: failed to get bus number\n", usbcore_name);
goto error_find_busnum;
}
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index 4684734..2ab8228 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -349,7 +349,8 @@ struct mon_bus *mon_bus_lookup(unsigned int num)
static int __init mon_init(void)
{
struct usb_bus *ubus;
- int rc, id;
+ int rc;
+ unsigned long id;
if ((rc = mon_text_init()) != 0)
goto err_text;
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index bb34f9f..a9bf11d 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -88,18 +88,19 @@ static int allocate_minors(struct usb_serial *serial, int num_ports)
{
struct usb_serial_port *port;
unsigned int i, j;
- int minor;
+ unsigned long idr_index;
+ int ret;
dev_dbg(&serial->interface->dev, "%s %d\n", __func__, num_ports);
mutex_lock(&table_lock);
for (i = 0; i < num_ports; ++i) {
port = serial->port[i];
- minor = idr_alloc(&serial_minors, port, 0,
+ ret = idr_alloc(&serial_minors, port, &idr_index, 0,
USB_SERIAL_TTY_MINORS, GFP_KERNEL);
- if (minor < 0)
+ if (ret)
goto error;
- port->minor = minor;
+ port->minor = idr_index;
port->port_number = i;
}
serial->minors_reserved = 1;
@@ -110,7 +111,7 @@ static int allocate_minors(struct usb_serial *serial, int num_ports)
for (j = 0; j < i; ++j)
idr_remove(&serial_minors, serial->port[j]->minor);
mutex_unlock(&table_lock);
- return minor;
+ return ret;
}
static void release_minors(struct usb_serial *serial)
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index 330d505..4ca1d55 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -268,9 +268,11 @@ void vfio_unregister_iommu_driver(const struct vfio_iommu_driver_ops *ops)
/**
* Group minor allocation/free - both called with vfio.group_lock held
*/
-static int vfio_alloc_group_minor(struct vfio_group *group)
+static int vfio_alloc_group_minor(struct vfio_group *group,
+ unsigned long *index)
{
- return idr_alloc(&vfio.group_idr, group, 0, MINORMASK + 1, GFP_KERNEL);
+ return idr_alloc(&vfio.group_idr, group, index, 0, MINORMASK + 1,
+ GFP_KERNEL);
}
static void vfio_free_group_minor(int minor)
@@ -324,7 +326,8 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
{
struct vfio_group *group, *tmp;
struct device *dev;
- int ret, minor;
+ unsigned long minor;
+ int ret;
group = kzalloc(sizeof(*group), GFP_KERNEL);
if (!group)
@@ -369,10 +372,10 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
}
}
- minor = vfio_alloc_group_minor(group);
- if (minor < 0) {
+ ret = vfio_alloc_group_minor(group, &minor);
+ if (ret) {
vfio_group_unlock_and_free(group);
- return ERR_PTR(minor);
+ return ERR_PTR(ret);
}
dev = device_create(vfio.class, NULL,
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index 6df3322..3e44d7f 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -1184,6 +1184,7 @@ static void detach_lkb(struct dlm_lkb *lkb)
static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
{
struct dlm_lkb *lkb;
+ unsigned long idr_index;
int rv;
lkb = dlm_allocate_lkb(ls);
@@ -1202,13 +1203,13 @@ static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
idr_preload(GFP_NOFS);
spin_lock(&ls->ls_lkbidr_spin);
- rv = idr_alloc(&ls->ls_lkbidr, lkb, 1, 0, GFP_NOWAIT);
- if (rv >= 0)
- lkb->lkb_id = rv;
+ rv = idr_alloc(&ls->ls_lkbidr, lkb, &idr_index, 1, 0, GFP_NOWAIT);
+ if (rv == 0)
+ lkb->lkb_id = idr_index;
spin_unlock(&ls->ls_lkbidr_spin);
idr_preload_end();
- if (rv < 0) {
+ if (rv) {
log_error(ls, "create_lkb idr error %d", rv);
return rv;
}
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index 91592b7..830f2e2 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -717,19 +717,19 @@ int dlm_new_lockspace(const char *name, const char *cluster,
return error;
}
-static int lkb_idr_is_local(int id, void *p, void *data)
+static int lkb_idr_is_local(unsigned long id, void *p, void *data)
{
struct dlm_lkb *lkb = p;
return lkb->lkb_nodeid == 0 && lkb->lkb_grmode != DLM_LOCK_IV;
}
-static int lkb_idr_is_any(int id, void *p, void *data)
+static int lkb_idr_is_any(unsigned long id, void *p, void *data)
{
return 1;
}
-static int lkb_idr_free(int id, void *p, void *data)
+static int lkb_idr_free(unsigned long id, void *p, void *data)
{
struct dlm_lkb *lkb = p;
diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c
index eaea789..6175536 100644
--- a/fs/dlm/recover.c
+++ b/fs/dlm/recover.c
@@ -305,6 +305,7 @@ static int recover_idr_empty(struct dlm_ls *ls)
static int recover_idr_add(struct dlm_rsb *r)
{
struct dlm_ls *ls = r->res_ls;
+ unsigned long idr_index;
int rv;
idr_preload(GFP_NOFS);
@@ -313,14 +314,13 @@ static int recover_idr_add(struct dlm_rsb *r)
rv = -1;
goto out_unlock;
}
- rv = idr_alloc(&ls->ls_recover_idr, r, 1, 0, GFP_NOWAIT);
- if (rv < 0)
+ rv = idr_alloc(&ls->ls_recover_idr, r, &idr_index, 1, 0, GFP_NOWAIT);
+ if (rv)
goto out_unlock;
- r->res_id = rv;
+ r->res_id = idr_index;
ls->ls_recover_list_count++;
dlm_hold_rsb(r);
- rv = 0;
out_unlock:
spin_unlock(&ls->ls_recover_idr_lock);
idr_preload_end();
@@ -353,7 +353,7 @@ static struct dlm_rsb *recover_idr_find(struct dlm_ls *ls, uint64_t id)
static void recover_idr_clear(struct dlm_ls *ls)
{
struct dlm_rsb *r;
- int id;
+ unsigned long id;
spin_lock(&ls->ls_recover_idr_lock);
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index e9bea90..7a45ccb 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -27,18 +27,19 @@
static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
{
int ret = 0;
+ unsigned long idr_index;
struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
if (clp->rpc_ops->version != 4 || minorversion != 0)
return ret;
idr_preload(GFP_KERNEL);
spin_lock(&nn->nfs_client_lock);
- ret = idr_alloc(&nn->cb_ident_idr, clp, 1, 0, GFP_NOWAIT);
- if (ret >= 0)
- clp->cl_cb_ident = ret;
+ ret = idr_alloc(&nn->cb_ident_idr, clp, &idr_index, 1, 0, GFP_NOWAIT);
+ if (ret == 0)
+ clp->cl_cb_ident = idr_index;
spin_unlock(&nn->nfs_client_lock);
idr_preload_end();
- return ret < 0 ? ret : 0;
+ return ret;
}
#ifdef CONFIG_NFS_V4_1
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 0c04f81..cf14954 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -637,7 +637,8 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *sla
void (*sc_free)(struct nfs4_stid *))
{
struct nfs4_stid *stid;
- int new_id;
+ unsigned long new_id;
+ int ret;
stid = kmem_cache_zalloc(slab, GFP_KERNEL);
if (!stid)
@@ -645,10 +646,11 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *sla
idr_preload(GFP_KERNEL);
spin_lock(&cl->cl_lock);
- new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 0, 0, GFP_NOWAIT);
+ ret = idr_alloc_cyclic(&cl->cl_stateids, stid, &new_id, 0, 0,
+ GFP_NOWAIT);
spin_unlock(&cl->cl_lock);
idr_preload_end();
- if (new_id < 0)
+ if (ret)
goto out_free;
stid->sc_free = sc_free;
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c
index 8b73332..4bc9b40 100644
--- a/fs/notify/inotify/inotify_fsnotify.c
+++ b/fs/notify/inotify/inotify_fsnotify.c
@@ -134,7 +134,7 @@ static void inotify_freeing_mark(struct fsnotify_mark *fsn_mark, struct fsnotify
* torn down. This is only called if the idr is about to be freed but there
* are still marks in it.
*/
-static int idr_callback(int id, void *p, void *data)
+static int idr_callback(unsigned long id, void *p, void *data)
{
struct fsnotify_mark *fsn_mark;
struct inotify_inode_mark *i_mark;
@@ -147,7 +147,7 @@ static int idr_callback(int id, void *p, void *data)
fsn_mark = p;
i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
- WARN(1, "inotify closing but id=%d for fsn_mark=%p in group=%p still in "
+ WARN(1, "inotify closing but id=%lu for fsn_mark=%p in group=%p still in "
"idr. Probably leaking memory\n", id, p, data);
/*
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 7cc7d3f..95915f8 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -345,20 +345,21 @@ static int inotify_add_to_idr(struct idr *idr, spinlock_t *idr_lock,
struct inotify_inode_mark *i_mark)
{
int ret;
+ unsigned long idr_index;
idr_preload(GFP_KERNEL);
spin_lock(idr_lock);
- ret = idr_alloc_cyclic(idr, i_mark, 1, 0, GFP_NOWAIT);
- if (ret >= 0) {
+ ret = idr_alloc_cyclic(idr, i_mark, &idr_index, 1, 0, GFP_NOWAIT);
+ if (ret == 0) {
/* we added the mark to the idr, take a reference */
- i_mark->wd = ret;
+ i_mark->wd = idr_index;
fsnotify_get_mark(&i_mark->fsn_mark);
}
spin_unlock(idr_lock);
idr_preload_end();
- return ret < 0 ? ret : 0;
+ return ret;
}
static struct inotify_inode_mark *inotify_idr_find_locked(struct fsnotify_group *group,
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index 8d77922..27ff262 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -306,15 +306,17 @@ static u8 o2net_num_from_nn(struct o2net_node *nn)
static int o2net_prep_nsw(struct o2net_node *nn, struct o2net_status_wait *nsw)
{
int ret;
+ unsigned long idr_index;
spin_lock(&nn->nn_lock);
- ret = idr_alloc(&nn->nn_status_idr, nsw, 0, 0, GFP_ATOMIC);
- if (ret >= 0) {
- nsw->ns_id = ret;
+ ret = idr_alloc(&nn->nn_status_idr, nsw, &idr_index, 0, 0,
+ GFP_ATOMIC);
+ if (ret == 0) {
+ nsw->ns_id = idr_index;
list_add_tail(&nsw->ns_node_item, &nn->nn_status_list);
}
spin_unlock(&nn->nn_lock);
- if (ret < 0)
+ if (ret)
return ret;
init_waitqueue_head(&nsw->ns_wq);
diff --git a/include/linux/idr.h b/include/linux/idr.h
index bf70b3e..1845576 100644
--- a/include/linux/idr.h
+++ b/include/linux/idr.h
@@ -18,7 +18,7 @@
struct idr {
struct radix_tree_root idr_rt;
- unsigned int idr_next;
+ unsigned long idr_next;
};
/*
@@ -57,7 +57,7 @@ static inline unsigned int idr_get_cursor(const struct idr *idr)
* The next call to idr_alloc_cyclic() will return @val if it is free
* (otherwise the search will start from this position).
*/
-static inline void idr_set_cursor(struct idr *idr, unsigned int val)
+static inline void idr_set_cursor(struct idr *idr, unsigned long val)
{
WRITE_ONCE(idr->idr_next, val);
}
@@ -80,15 +80,17 @@ static inline void idr_set_cursor(struct idr *idr, unsigned int val)
*/
void idr_preload(gfp_t gfp_mask);
-int idr_alloc(struct idr *, void *entry, int start, int end, gfp_t);
-int idr_alloc_cyclic(struct idr *, void *entry, int start, int end, gfp_t);
-int idr_for_each(const struct idr *,
- int (*fn)(int id, void *p, void *data), void *data);
-void *idr_get_next(struct idr *, int *nextid);
-void *idr_replace(struct idr *, void *, int id);
-void idr_destroy(struct idr *);
-
-static inline void *idr_remove(struct idr *idr, int id)
+int idr_alloc(struct idr *idr, void *ptr, unsigned long *index,
+ unsigned long start, unsigned long end, gfp_t gfp);
+int idr_alloc_cyclic(struct idr *idr, void *entry, unsigned long *index,
+ unsigned long start, unsigned long end, gfp_t gfp);
+int idr_for_each(const struct idr *idr,
+ int (*fn)(unsigned long id, void *p, void *data), void *data);
+void *idr_get_next(struct idr *idr, unsigned long *nextid);
+void *idr_replace(struct idr *idr, void *ptr, unsigned long id);
+void idr_destroy(struct idr *idr);
+
+static inline void *idr_remove(struct idr *idr, unsigned long id)
{
return radix_tree_delete_item(&idr->idr_rt, id, NULL);
}
@@ -128,7 +130,7 @@ static inline void idr_preload_end(void)
* This function can be called under rcu_read_lock(), given that the leaf
* pointers lifetimes are correctly managed.
*/
-static inline void *idr_find(const struct idr *idr, int id)
+static inline void *idr_find(const struct idr *idr, unsigned long id)
{
return radix_tree_lookup(&idr->idr_rt, id);
}
diff --git a/include/linux/of.h b/include/linux/of.h
index 4a8a709..ceb14bf 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -1307,7 +1307,7 @@ struct of_overlay_notify_data {
#ifdef CONFIG_OF_OVERLAY
/* ID based overlays; the API for external users */
-int of_overlay_create(struct device_node *tree);
+int of_overlay_create(struct device_node *tree, *unsigned long *id);
int of_overlay_destroy(int id);
int of_overlay_destroy_all(void);
@@ -1316,7 +1316,7 @@ struct of_overlay_notify_data {
#else
-static inline int of_overlay_create(struct device_node *tree)
+static inline int of_overlay_create(struct device_node *tree, unsigned long *id)
{
return -ENOTSUPP;
}
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index 3e57350..14874e2 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -358,7 +358,7 @@ int radix_tree_split(struct radix_tree_root *, unsigned long index,
int radix_tree_join(struct radix_tree_root *, unsigned long index,
unsigned new_order, void *);
void __rcu **idr_get_free(struct radix_tree_root *, struct radix_tree_iter *,
- gfp_t, int end);
+ gfp_t, unsigned long end);
enum {
RADIX_TREE_ITER_TAG_MASK = 0x0f, /* tag index in lower nybble */
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index b8eb51a..1bdc805 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -567,7 +567,7 @@ struct p9_fcall {
struct p9_idpool *p9_idpool_create(void);
void p9_idpool_destroy(struct p9_idpool *);
-int p9_idpool_get(struct p9_idpool *p);
+int p9_idpool_get(struct p9_idpool *p, int *index);
void p9_idpool_put(int id, struct p9_idpool *p);
int p9_idpool_check(int id, struct p9_idpool *p);
diff --git a/ipc/msg.c b/ipc/msg.c
index 2c38f10..31013ff 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -143,7 +143,7 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
/* ipc_addid() locks msq upon success. */
retval = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
- if (retval < 0) {
+ if (retval) {
call_rcu(&msq->q_perm.rcu, msg_rcu_free);
return retval;
}
diff --git a/ipc/sem.c b/ipc/sem.c
index 38371e9..5144ccd 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -514,7 +514,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
sma->sem_ctime = get_seconds();
retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
- if (retval < 0) {
+ if (retval) {
call_rcu(&sma->sem_perm.rcu, sem_rcu_free);
return retval;
}
diff --git a/ipc/shm.c b/ipc/shm.c
index 8828b4c..037b21f 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -298,7 +298,7 @@ static void shm_close(struct vm_area_struct *vma)
}
/* Called with ns->shm_ids(ns).rwsem locked */
-static int shm_try_destroy_orphaned(int id, void *p, void *data)
+static int shm_try_destroy_orphaned(unsigned long id, void *p, void *data)
{
struct ipc_namespace *ns = data;
struct kern_ipc_perm *ipcp = p;
@@ -599,7 +599,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
shp->shm_creator = current;
error = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
- if (error < 0)
+ if (error)
goto no_id;
list_add(&shp->shm_clist, ¤t->sysvshm.shm_clist);
diff --git a/ipc/util.c b/ipc/util.c
index 1a2cb02..5a46124 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -221,8 +221,9 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size)
{
kuid_t euid;
kgid_t egid;
- int id;
+ int ret;
int next_id = ids->next_id;
+ unsigned long idr_index;
if (size > IPCMNI)
size = IPCMNI;
@@ -242,14 +243,14 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size)
new->cuid = new->uid = euid;
new->gid = new->cgid = egid;
- id = idr_alloc(&ids->ipcs_idr, new,
- (next_id < 0) ? 0 : ipcid_to_idx(next_id), 0,
- GFP_NOWAIT);
+ ret = idr_alloc(&ids->ipcs_idr, new, &idr_index,
+ (next_id < 0) ? 0 : ipcid_to_idx(next_id), 0,
+ GFP_NOWAIT);
idr_preload_end();
- if (id < 0) {
+ if (ret) {
spin_unlock(&new->lock);
rcu_read_unlock();
- return id;
+ return ret;
}
ids->in_use++;
@@ -263,8 +264,8 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size)
ids->next_id = -1;
}
- new->id = ipc_buildid(id, new->seq);
- return id;
+ new->id = ipc_buildid(idr_index, new->seq);
+ return ret;
}
/**
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index fbe09a0..ba6b485 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -169,18 +169,19 @@ static void bpf_map_uncharge_memlock(struct bpf_map *map)
static int bpf_map_alloc_id(struct bpf_map *map)
{
- int id;
+ int ret;
+ unsigned long id;
spin_lock_bh(&map_idr_lock);
- id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC);
- if (id > 0)
+ ret = idr_alloc_cyclic(&map_idr, map, &id, 1, INT_MAX, GFP_ATOMIC);
+ if (ret == 0)
map->id = id;
spin_unlock_bh(&map_idr_lock);
if (WARN_ON_ONCE(!id))
return -ENOSPC;
- return id > 0 ? 0 : id;
+ return ret;
}
static void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock)
@@ -771,11 +772,12 @@ static void bpf_prog_uncharge_memlock(struct bpf_prog *prog)
static int bpf_prog_alloc_id(struct bpf_prog *prog)
{
- int id;
+ int ret;
+ unsigned long id;
spin_lock_bh(&prog_idr_lock);
- id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC);
- if (id > 0)
+ ret = idr_alloc_cyclic(&prog_idr, prog, &id, 1, INT_MAX, GFP_ATOMIC);
+ if (ret == 0)
prog->aux->id = id;
spin_unlock_bh(&prog_idr_lock);
@@ -783,7 +785,7 @@ static int bpf_prog_alloc_id(struct bpf_prog *prog)
if (WARN_ON_ONCE(!id))
return -ENOSPC;
- return id > 0 ? 0 : id;
+ return ret;
}
static void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
@@ -1202,7 +1204,7 @@ static int bpf_obj_get_next_id(const union bpf_attr *attr,
struct idr *idr,
spinlock_t *lock)
{
- u32 next_id = attr->start_id;
+ unsigned long next_id = attr->start_id;
int err = 0;
if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX)
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index df2e0f1..1d774c2 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -286,15 +286,18 @@ bool cgroup_on_dfl(const struct cgroup *cgrp)
}
/* IDR wrappers which synchronize using cgroup_idr_lock */
-static int cgroup_idr_alloc(struct idr *idr, void *ptr, int start, int end,
- gfp_t gfp_mask)
+static int cgroup_idr_alloc(struct idr *idr, void *ptr, int *index,
+ int start, int end, gfp_t gfp_mask)
{
int ret;
+ unsigned long idr_index;
idr_preload(gfp_mask);
spin_lock_bh(&cgroup_idr_lock);
- ret = idr_alloc(idr, ptr, start, end, gfp_mask & ~__GFP_DIRECT_RECLAIM);
+ ret = idr_alloc(idr, ptr, &idr_index, start, end,
+ gfp_mask & ~__GFP_DIRECT_RECLAIM);
spin_unlock_bh(&cgroup_idr_lock);
+ *index = idr_index;
idr_preload_end();
return ret;
}
@@ -1040,13 +1043,15 @@ struct cgroup_root *cgroup_root_from_kf(struct kernfs_root *kf_root)
static int cgroup_init_root_id(struct cgroup_root *root)
{
- int id;
+ int ret;
+ unsigned long id;
lockdep_assert_held(&cgroup_mutex);
- id = idr_alloc_cyclic(&cgroup_hierarchy_idr, root, 0, 0, GFP_KERNEL);
- if (id < 0)
- return id;
+ ret = idr_alloc_cyclic(&cgroup_hierarchy_idr, root, &id, 0, 0,
+ GFP_KERNEL);
+ if (ret)
+ return ret;
root->hierarchy_id = id;
return 0;
@@ -1703,14 +1708,15 @@ int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask, int ref_flags)
struct cgroup *root_cgrp = &root->cgrp;
struct kernfs_syscall_ops *kf_sops;
struct css_set *cset;
- int i, ret;
+ int i, ret, index;
lockdep_assert_held(&cgroup_mutex);
- ret = cgroup_idr_alloc(&root->cgroup_idr, root_cgrp, 1, 2, GFP_KERNEL);
- if (ret < 0)
+ ret = cgroup_idr_alloc(&root->cgroup_idr, root_cgrp, &index, 1, 2,
+ GFP_KERNEL);
+ if (ret)
goto out;
- root_cgrp->id = ret;
+ root_cgrp->id = index;
root_cgrp->ancestor_ids[0] = ret;
ret = percpu_ref_init(&root_cgrp->self.refcnt, css_release,
@@ -1955,7 +1961,7 @@ int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen)
{
struct cgroup_root *root;
struct cgroup *cgrp;
- int hierarchy_id = 1;
+ unsigned long hierarchy_id = 1;
int ret;
mutex_lock(&cgroup_mutex);
@@ -4127,7 +4133,7 @@ static struct cgroup_subsys_state *css_create(struct cgroup *cgrp,
struct cgroup *parent = cgroup_parent(cgrp);
struct cgroup_subsys_state *parent_css = cgroup_css(parent, ss);
struct cgroup_subsys_state *css;
- int err;
+ int err, index;
lockdep_assert_held(&cgroup_mutex);
@@ -4143,10 +4149,10 @@ static struct cgroup_subsys_state *css_create(struct cgroup *cgrp,
if (err)
goto err_free_css;
- err = cgroup_idr_alloc(&ss->css_idr, NULL, 2, 0, GFP_KERNEL);
- if (err < 0)
+ err = cgroup_idr_alloc(&ss->css_idr, NULL, &index, 2, 0, GFP_KERNEL);
+ if (err)
goto err_free_css;
- css->id = err;
+ css->id = index;
/* @css is ready to be brought online now, make it visible */
list_add_tail_rcu(&css->sibling, &parent_css->children);
@@ -4200,8 +4206,10 @@ static struct cgroup *cgroup_create(struct cgroup *parent)
* Temporarily set the pointer to NULL, so idr_find() won't return
* a half-baked cgroup.
*/
- cgrp->id = cgroup_idr_alloc(&root->cgroup_idr, NULL, 2, 0, GFP_KERNEL);
- if (cgrp->id < 0) {
+ ret = cgroup_idr_alloc(&root->cgroup_idr, NULL, &cgrp->id, 2, 0,
+ GFP_KERNEL);
+
+ if (ret) {
ret = -ENOMEM;
goto out_cancel_ref;
}
@@ -4501,6 +4509,7 @@ int cgroup_rmdir(struct kernfs_node *kn)
static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early)
{
struct cgroup_subsys_state *css;
+ int ret;
pr_debug("Initializing cgroup subsys %s\n", ss->name);
@@ -4526,8 +4535,9 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early)
/* allocation can't be done safely during early init */
css->id = 1;
} else {
- css->id = cgroup_idr_alloc(&ss->css_idr, css, 1, 2, GFP_KERNEL);
- BUG_ON(css->id < 0);
+ ret = cgroup_idr_alloc(&ss->css_idr, css, &css->id, 1, 2,
+ GFP_KERNEL);
+ WARN_ON(ret);
}
/* Update the init_css_set to contain a subsys
@@ -4598,6 +4608,7 @@ int __init cgroup_init_early(void)
int __init cgroup_init(void)
{
struct cgroup_subsys *ss;
+ int ret;
int ssid;
BUILD_BUG_ON(CGROUP_SUBSYS_COUNT > 16);
@@ -4631,9 +4642,9 @@ int __init cgroup_init(void)
struct cgroup_subsys_state *css =
init_css_set.subsys[ss->id];
- css->id = cgroup_idr_alloc(&ss->css_idr, css, 1, 2,
- GFP_KERNEL);
- BUG_ON(css->id < 0);
+ ret = cgroup_idr_alloc(&ss->css_idr, css, &css->id,
+ 1, 2, GFP_KERNEL);
+ WARN_ON(ret);
} else {
cgroup_init_subsys(ss, false);
}
diff --git a/kernel/events/core.c b/kernel/events/core.c
index a7a6c1d..4cb50bb 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -9013,6 +9013,7 @@ static int pmu_dev_alloc(struct pmu *pmu)
int perf_pmu_register(struct pmu *pmu, const char *name, int type)
{
int cpu, ret;
+ unsigned long idr_index;
mutex_lock(&pmus_lock);
ret = -ENOMEM;
@@ -9026,13 +9027,12 @@ int perf_pmu_register(struct pmu *pmu, const char *name, int type)
pmu->name = name;
if (type < 0) {
- type = idr_alloc(&pmu_idr, pmu, PERF_TYPE_MAX, 0, GFP_KERNEL);
- if (type < 0) {
- ret = type;
+ ret = idr_alloc(&pmu_idr, pmu, &idr_index, PERF_TYPE_MAX, 0,
+ GFP_KERNEL);
+ if (ret)
goto free_pdc;
- }
}
- pmu->type = type;
+ pmu->type = idr_index;
if (pmu_bus_running) {
ret = pmu_dev_alloc(pmu);
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index ca937b0..213b338 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -533,13 +533,14 @@ static inline void debug_work_deactivate(struct work_struct *work) { }
static int worker_pool_assign_id(struct worker_pool *pool)
{
int ret;
+ unsigned long idr_index;
lockdep_assert_held(&wq_pool_mutex);
- ret = idr_alloc(&worker_pool_idr, pool, 0, WORK_OFFQ_POOL_NONE,
- GFP_KERNEL);
- if (ret >= 0) {
- pool->id = ret;
+ ret = idr_alloc(&worker_pool_idr, pool, &idr_index, 0,
+ WORK_OFFQ_POOL_NONE, GFP_KERNEL);
+ if (ret == 0) {
+ pool->id = idr_index;
return 0;
}
return ret;
@@ -4427,7 +4428,7 @@ void show_workqueue_state(void)
struct workqueue_struct *wq;
struct worker_pool *pool;
unsigned long flags;
- int pi;
+ unsigned long pi;
rcu_read_lock_sched();
@@ -4674,7 +4675,7 @@ int workqueue_online_cpu(unsigned int cpu)
{
struct worker_pool *pool;
struct workqueue_struct *wq;
- int pi;
+ unsigned long pi;
mutex_lock(&wq_pool_mutex);
@@ -5380,7 +5381,7 @@ static void wq_watchdog_timer_fn(unsigned long data)
unsigned long thresh = READ_ONCE(wq_watchdog_thresh) * HZ;
bool lockup_detected = false;
struct worker_pool *pool;
- int pi;
+ unsigned long pi;
if (!thresh)
return;
diff --git a/lib/idr.c b/lib/idr.c
index b13682b..e941cd1 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -11,12 +11,13 @@
* idr_alloc - allocate an id
* @idr: idr handle
* @ptr: pointer to be associated with the new id
+ * @index: pointer to return allocated id, could be NULL
* @start: the minimum id (inclusive)
* @end: the maximum id (exclusive)
* @gfp: memory allocation flags
*
* Allocates an unused ID in the range [start, end). Returns -ENOSPC
- * if there are no unused IDs in that range.
+ * if there are no unused IDs in that range. Return 0 for success.
*
* Note that @end is treated as max when <= 0. This is to always allow
* using @start + N as @end as long as N is inside integer range.
@@ -26,13 +27,12 @@
* concurrently with read-only accesses to the @idr, such as idr_find() and
* idr_for_each_entry().
*/
-int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp)
+int idr_alloc(struct idr *idr, void *ptr, unsigned long *index,
+ unsigned long start, unsigned long end, gfp_t gfp)
{
void __rcu **slot;
struct radix_tree_iter iter;
- if (WARN_ON_ONCE(start < 0))
- return -EINVAL;
if (WARN_ON_ONCE(radix_tree_is_internal_node(ptr)))
return -EINVAL;
@@ -43,7 +43,10 @@ int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp)
radix_tree_iter_replace(&idr->idr_rt, &iter, slot, ptr);
radix_tree_iter_tag_clear(&idr->idr_rt, &iter, IDR_FREE);
- return iter.index;
+
+ if (index)
+ *index = iter.index;
+ return 0;
}
EXPORT_SYMBOL_GPL(idr_alloc);
@@ -51,6 +54,7 @@ int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp)
* idr_alloc_cyclic - allocate new idr entry in a cyclical fashion
* @idr: idr handle
* @ptr: pointer to be associated with the new id
+ * @index: pointer to return allocated id, could be NULL
* @start: the minimum id (inclusive)
* @end: the maximum id (exclusive)
* @gfp: memory allocation flags
@@ -59,21 +63,23 @@ int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp)
* If not, it will attempt to allocate the smallest ID that is larger or
* equal to @start.
*/
-int idr_alloc_cyclic(struct idr *idr, void *ptr, int start, int end, gfp_t gfp)
+int idr_alloc_cyclic(struct idr *idr, void *ptr, unsigned long *index,
+ unsigned long start, unsigned long end, gfp_t gfp)
{
- int id, curr = idr->idr_next;
+ int ret;
+ unsigned long curr = idr->idr_next;
if (curr < start)
curr = start;
- id = idr_alloc(idr, ptr, curr, end, gfp);
- if ((id == -ENOSPC) && (curr > start))
- id = idr_alloc(idr, ptr, start, curr, gfp);
+ ret = idr_alloc(idr, ptr, index, curr, end, gfp);
+ if (ret == -ENOSPC && curr > start)
+ ret = idr_alloc(idr, ptr, index, start, curr, gfp);
- if (id >= 0)
- idr->idr_next = id + 1U;
+ if (*index >= 0)
+ idr->idr_next = *index + 1UL;
- return id;
+ return ret;
}
EXPORT_SYMBOL(idr_alloc_cyclic);
@@ -95,7 +101,7 @@ int idr_alloc_cyclic(struct idr *idr, void *ptr, int start, int end, gfp_t gfp)
* will not cause other entries to be skipped, nor spurious ones to be seen.
*/
int idr_for_each(const struct idr *idr,
- int (*fn)(int id, void *p, void *data), void *data)
+ int (*fn)(unsigned long id, void *p, void *data), void *data)
{
struct radix_tree_iter iter;
void __rcu **slot;
@@ -120,7 +126,7 @@ int idr_for_each(const struct idr *idr,
* to the ID of the found value. To use in a loop, the value pointed to by
* nextid must be incremented by the user.
*/
-void *idr_get_next(struct idr *idr, int *nextid)
+void *idr_get_next(struct idr *idr, unsigned long *nextid)
{
struct radix_tree_iter iter;
void __rcu **slot;
@@ -148,7 +154,7 @@ void *idr_get_next(struct idr *idr, int *nextid)
* Returns: 0 on success. %-ENOENT indicates that @id was not found.
* %-EINVAL indicates that @id or @ptr were not valid.
*/
-void *idr_replace(struct idr *idr, void *ptr, int id)
+void *idr_replace(struct idr *idr, void *ptr, unsigned long id)
{
struct radix_tree_node *node;
void __rcu **slot = NULL;
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 898e879..87d8748 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -2138,12 +2138,13 @@ int ida_pre_get(struct ida *ida, gfp_t gfp)
EXPORT_SYMBOL(ida_pre_get);
void __rcu **idr_get_free(struct radix_tree_root *root,
- struct radix_tree_iter *iter, gfp_t gfp, int end)
+ struct radix_tree_iter *iter, gfp_t gfp,
+ unsigned long end)
{
struct radix_tree_node *node = NULL, *child;
void __rcu **slot = (void __rcu **)&root->rnode;
unsigned long maxindex, start = iter->next_index;
- unsigned long max = end > 0 ? end - 1 : INT_MAX;
+ unsigned long max = end - 1;
unsigned int shift, offset = 0;
grow:
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 3df3c04..5b310ec 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -4166,6 +4166,8 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
struct mem_cgroup *memcg;
size_t size;
int node;
+ unsigned long idr_index;
+ int ret;
size = sizeof(struct mem_cgroup);
size += nr_node_ids * sizeof(struct mem_cgroup_per_node *);
@@ -4174,11 +4176,12 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
if (!memcg)
return NULL;
- memcg->id.id = idr_alloc(&mem_cgroup_idr, NULL,
- 1, MEM_CGROUP_ID_MAX,
- GFP_KERNEL);
- if (memcg->id.id < 0)
+ ret = idr_alloc(&mem_cgroup_idr, NULL,
+ &idr_index, 1, MEM_CGROUP_ID_MAX,
+ GFP_KERNEL);
+ if (ret)
goto fail;
+ memcg->id.id = idr_index;
memcg->stat = alloc_percpu(struct mem_cgroup_stat_cpu);
if (!memcg->stat)
diff --git a/net/9p/client.c b/net/9p/client.c
index 4674235..484de6e6 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -361,14 +361,15 @@ struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag)
static int p9_tag_init(struct p9_client *c)
{
int err = 0;
+ int index;
c->tagpool = p9_idpool_create();
if (IS_ERR(c->tagpool)) {
err = PTR_ERR(c->tagpool);
goto error;
}
- err = p9_idpool_get(c->tagpool); /* reserve tag 0 */
- if (err < 0) {
+ err = p9_idpool_get(c->tagpool, &index); /* reserve tag 0 */
+ if (err) {
p9_idpool_destroy(c->tagpool);
goto error;
}
@@ -714,8 +715,8 @@ static struct p9_req_t *p9_client_prepare_req(struct p9_client *c,
tag = P9_NOTAG;
if (type != P9_TVERSION) {
- tag = p9_idpool_get(c->tagpool);
- if (tag < 0)
+ err = p9_idpool_get(c->tagpool, &tag);
+ if (err)
return ERR_PTR(-ENOMEM);
}
@@ -905,7 +906,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
static struct p9_fid *p9_fid_create(struct p9_client *clnt)
{
- int ret;
+ int ret, index;
struct p9_fid *fid;
unsigned long flags;
@@ -914,12 +915,12 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt)
if (!fid)
return ERR_PTR(-ENOMEM);
- ret = p9_idpool_get(clnt->fidpool);
- if (ret < 0) {
+ ret = p9_idpool_get(clnt->fidpool, &index);
+ if (ret) {
ret = -ENOSPC;
goto error;
}
- fid->fid = ret;
+ fid->fid = index;
memset(&fid->qid, 0, sizeof(struct p9_qid));
fid->mode = -1;
diff --git a/net/9p/util.c b/net/9p/util.c
index 59f278e..328fdcb 100644
--- a/net/9p/util.c
+++ b/net/9p/util.c
@@ -85,24 +85,26 @@ void p9_idpool_destroy(struct p9_idpool *p)
* the lock included in struct idr?
*/
-int p9_idpool_get(struct p9_idpool *p)
+int p9_idpool_get(struct p9_idpool *p, int *index)
{
- int i;
+ int ret;
+ unsigned long idr_index;
unsigned long flags;
idr_preload(GFP_NOFS);
spin_lock_irqsave(&p->lock, flags);
/* no need to store exactly p, we just need something non-null */
- i = idr_alloc(&p->pool, p, 0, 0, GFP_NOWAIT);
+ ret = idr_alloc(&p->pool, p, &idr_index, 0, 0, GFP_NOWAIT);
+ *index = idr_index;
spin_unlock_irqrestore(&p->lock, flags);
idr_preload_end();
- if (i < 0)
+ if (ret)
return -1;
- p9_debug(P9_DEBUG_MUX, " id %d pool %p\n", i, p);
- return i;
+ p9_debug(P9_DEBUG_MUX, " ret %d id %d pool %p\n", ret, *index, p);
+ return ret;
}
EXPORT_SYMBOL(p9_idpool_get);
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 6cfdc7c..a1cee8a 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -156,7 +156,8 @@ static void ops_free_list(const struct pernet_operations *ops,
}
/* should be called with nsid_lock held */
-static int alloc_netid(struct net *net, struct net *peer, int reqid)
+static int alloc_netid(struct net *net, struct net *peer, int reqid,
+ unsigned long *index)
{
int min = 0, max = 0;
@@ -165,7 +166,7 @@ static int alloc_netid(struct net *net, struct net *peer, int reqid)
max = reqid + 1;
}
- return idr_alloc(&net->netns_ids, peer, min, max, GFP_ATOMIC);
+ return idr_alloc(&net->netns_ids, peer, index, min, max, GFP_ATOMIC);
}
/* This function is used by idr_for_each(). If net is equal to peer, the
@@ -174,7 +175,7 @@ static int alloc_netid(struct net *net, struct net *peer, int reqid)
* NET_ID_ZERO (-1) for it.
*/
#define NET_ID_ZERO -1
-static int net_eq_idr(int id, void *net, void *peer)
+static int net_eq_idr(unsigned long id, void *net, void *peer)
{
if (net_eq(net, peer))
return id ? : NET_ID_ZERO;
@@ -189,6 +190,8 @@ static int __peernet2id_alloc(struct net *net, struct net *peer, bool *alloc)
{
int id = idr_for_each(&net->netns_ids, net_eq_idr, peer);
bool alloc_it = *alloc;
+ unsigned long index;
+ int ret;
*alloc = false;
@@ -199,9 +202,9 @@ static int __peernet2id_alloc(struct net *net, struct net *peer, bool *alloc)
return id;
if (alloc_it) {
- id = alloc_netid(net, peer, -1);
+ ret = alloc_netid(net, peer, -1, &index);
*alloc = true;
- return id >= 0 ? id : NETNSA_NSID_NOT_ASSIGNED;
+ return ret == 0 ? index : NETNSA_NSID_NOT_ASSIGNED;
}
return NETNSA_NSID_NOT_ASSIGNED;
@@ -616,6 +619,7 @@ static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr *nla;
struct net *peer;
int nsid, err;
+ unsigned long index;
err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
rtnl_net_policy, extack);
@@ -653,11 +657,10 @@ static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh,
goto out;
}
- err = alloc_netid(net, peer, nsid);
+ err = alloc_netid(net, peer, nsid, &index);
spin_unlock_bh(&net->nsid_lock);
- if (err >= 0) {
- rtnl_net_notifyid(net, RTM_NEWNSID, err);
- err = 0;
+ if (err == 0) {
+ rtnl_net_notifyid(net, RTM_NEWNSID, index);
} else if (err == -ENOSPC && nsid >= 0) {
err = -EEXIST;
NL_SET_BAD_ATTR(extack, tb[NETNSA_NSID]);
@@ -760,7 +763,7 @@ struct rtnl_net_dump_cb {
int s_idx;
};
-static int rtnl_net_dumpid_one(int id, void *peer, void *data)
+static int rtnl_net_dumpid_one(unsigned long id, void *peer, void *data)
{
struct rtnl_net_dump_cb *net_cb = (struct rtnl_net_dump_cb *)data;
int ret;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a354f19..e96ffe5 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -266,6 +266,7 @@ static int ieee80211_add_nan_func(struct wiphy *wiphy,
struct cfg80211_nan_func *nan_func)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+ unsigned long idr_index;
int ret;
if (sdata->vif.type != NL80211_IFTYPE_NAN)
@@ -276,15 +277,14 @@ static int ieee80211_add_nan_func(struct wiphy *wiphy,
spin_lock_bh(&sdata->u.nan.func_lock);
- ret = idr_alloc(&sdata->u.nan.function_inst_ids,
- nan_func, 1, sdata->local->hw.max_nan_de_entries + 1,
- GFP_ATOMIC);
+ ret = idr_alloc(&sdata->u.nan.function_inst_ids, nan_func, &idr_index,
+ 1, sdata->local->hw.max_nan_de_entries + 1, GFP_ATOMIC);
spin_unlock_bh(&sdata->u.nan.func_lock);
- if (ret < 0)
+ if (ret)
return ret;
- nan_func->instance_id = ret;
+ nan_func->instance_id = idr_index;
WARN_ON(nan_func->instance_id == 0);
@@ -304,7 +304,7 @@ static int ieee80211_add_nan_func(struct wiphy *wiphy,
u64 cookie)
{
struct cfg80211_nan_func *func;
- int id;
+ unsigned long id;
lockdep_assert_held(&sdata->u.nan.func_lock);
@@ -3266,23 +3266,24 @@ int ieee80211_attach_ack_skb(struct ieee80211_local *local, struct sk_buff *skb,
{
unsigned long spin_flags;
struct sk_buff *ack_skb;
- int id;
+ unsigned long idr_index;
+ int ret;
ack_skb = skb_copy(skb, gfp);
if (!ack_skb)
return -ENOMEM;
spin_lock_irqsave(&local->ack_status_lock, spin_flags);
- id = idr_alloc(&local->ack_status_frames, ack_skb,
- 1, 0x10000, GFP_ATOMIC);
+ ret = idr_alloc(&local->ack_status_frames, ack_skb, &idr_index,
+ 1, 0x10000, GFP_ATOMIC);
spin_unlock_irqrestore(&local->ack_status_lock, spin_flags);
- if (id < 0) {
+ if (ret) {
kfree_skb(ack_skb);
return -ENOMEM;
}
- IEEE80211_SKB_CB(skb)->ack_frame_id = id;
+ IEEE80211_SKB_CB(skb)->ack_frame_id = idr_index;
*cookie = ieee80211_mgmt_tx_cookie(local);
IEEE80211_SKB_CB(ack_skb)->ack.cookie = *cookie;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 9228ac7..517421c 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -797,11 +797,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
unsigned long flags;
struct sk_buff *skb, *tmp;
u32 hw_reconf_flags = 0;
- int i, flushed;
+ int flushed;
struct ps_data *ps;
struct cfg80211_chan_def chandef;
bool cancel_scan;
struct cfg80211_nan_func *func;
+ unsigned long i;
clear_bit(SDATA_STATE_RUNNING, &sdata->state);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 8aa1f5b..4195df2 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1209,7 +1209,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL(ieee80211_unregister_hw);
-static int ieee80211_free_ack_frame(int id, void *p, void *data)
+static int ieee80211_free_ack_frame(unsigned long id, void *p, void *data)
{
WARN_ONCE(1, "Have pending ack frames!\n");
kfree_skb(p);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 8858f4f..7aa02b6 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2373,6 +2373,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_sub_if_data *ap_sdata;
enum nl80211_band band;
+ unsigned long idr_index;
int ret;
if (IS_ERR(sta))
@@ -2623,11 +2624,11 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
spin_lock_irqsave(&local->ack_status_lock, flags);
id = idr_alloc(&local->ack_status_frames, ack_skb,
- 1, 0x10000, GFP_ATOMIC);
+ &idr_index, 1, 0x10000, GFP_ATOMIC);
spin_unlock_irqrestore(&local->ack_status_lock, flags);
- if (id >= 0) {
- info_id = id;
+ if (id == 0) {
+ info_id = idr_index;
info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
} else {
kfree_skb(ack_skb);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 259698d..4af5d5e 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1755,7 +1755,8 @@ static void ieee80211_reconfig_stations(struct ieee80211_sub_if_data *sdata)
static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data *sdata)
{
struct cfg80211_nan_func *func, **funcs;
- int res, id, i = 0;
+ int res, i = 0;
+ unsigned long id;
res = drv_start_nan(sdata->local, sdata,
&sdata->u.nan.conf);
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 10f8b4c..76f0bc4 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -97,7 +97,7 @@ static const struct genl_family *genl_family_find_byid(unsigned int id)
static const struct genl_family *genl_family_find_byname(char *name)
{
const struct genl_family *family;
- unsigned int id;
+ unsigned long id;
idr_for_each_entry(&genl_fam_idr, family, id)
if (strcmp(family->name, name) == 0)
@@ -322,6 +322,7 @@ int genl_register_family(struct genl_family *family)
{
int err, i;
int start = GENL_START_ALLOC, end = GENL_MAX_ID;
+ unsigned long idr_index;
err = genl_validate_ops(family);
if (err)
@@ -360,12 +361,11 @@ int genl_register_family(struct genl_family *family)
} else
family->attrbuf = NULL;
- family->id = idr_alloc(&genl_fam_idr, family,
- start, end + 1, GFP_KERNEL);
- if (family->id < 0) {
- err = family->id;
+ err = idr_alloc(&genl_fam_idr, family, &idr_index,
+ start, end + 1, GFP_KERNEL);
+ if (err)
goto errout_locked;
- }
+ family->id = idr_index;
err = genl_validate_assign_mc_groups(family);
if (err)
@@ -775,7 +775,7 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
struct genl_family *rt;
struct net *net = sock_net(skb->sk);
int fams_to_skip = cb->args[0];
- unsigned int id;
+ unsigned long id;
idr_for_each_entry(&genl_fam_idr, rt, id) {
if (!rt->netnsok && !net_eq(net, &init_net))
@@ -961,7 +961,7 @@ static int genl_bind(struct net *net, int group)
{
struct genl_family *f;
int err = -ENOENT;
- unsigned int id;
+ unsigned long id;
down_read(&cb_lock);
@@ -987,7 +987,7 @@ static int genl_bind(struct net *net, int group)
static void genl_unbind(struct net *net, int group)
{
struct genl_family *f;
- unsigned int id;
+ unsigned long id;
down_read(&cb_lock);
diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c
index c2f5c13..939ee02 100644
--- a/net/qrtr/qrtr.c
+++ b/net/qrtr/qrtr.c
@@ -498,28 +498,31 @@ static void qrtr_port_remove(struct qrtr_sock *ipc)
static int qrtr_port_assign(struct qrtr_sock *ipc, int *port)
{
int rc;
+ unsigned long idr_index;
mutex_lock(&qrtr_port_lock);
if (!*port) {
- rc = idr_alloc(&qrtr_ports, ipc,
+ rc = idr_alloc(&qrtr_ports, ipc, &idr_index,
QRTR_MIN_EPH_SOCKET, QRTR_MAX_EPH_SOCKET + 1,
GFP_ATOMIC);
- if (rc >= 0)
- *port = rc;
+ if (rc == 0)
+ *port = idr_index;
} else if (*port < QRTR_MIN_EPH_SOCKET && !capable(CAP_NET_ADMIN)) {
rc = -EACCES;
} else if (*port == QRTR_PORT_CTRL) {
- rc = idr_alloc(&qrtr_ports, ipc, 0, 1, GFP_ATOMIC);
+ rc = idr_alloc(&qrtr_ports, ipc, NULL, 0, 1,
+ GFP_ATOMIC);
} else {
- rc = idr_alloc(&qrtr_ports, ipc, *port, *port + 1, GFP_ATOMIC);
- if (rc >= 0)
- *port = rc;
+ rc = idr_alloc(&qrtr_ports, ipc, &idr_index, *port,
+ *port + 1, GFP_ATOMIC);
+ if (rc == 0)
+ *port = idr_index;
}
mutex_unlock(&qrtr_port_lock);
if (rc == -ENOSPC)
return -EADDRINUSE;
- else if (rc < 0)
+ else if (rc)
return rc;
sock_hold(&ipc->sk);
@@ -531,7 +534,7 @@ static int qrtr_port_assign(struct qrtr_sock *ipc, int *port)
static void qrtr_reset_ports(void)
{
struct qrtr_sock *ipc;
- int id;
+ unsigned long id;
mutex_lock(&qrtr_port_lock);
idr_for_each_entry(&qrtr_ports, ipc, id) {
diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c
index eb21576..8f49e9c 100644
--- a/net/rxrpc/conn_client.c
+++ b/net/rxrpc/conn_client.c
@@ -106,16 +106,17 @@ static int rxrpc_get_client_connection_id(struct rxrpc_connection *conn,
gfp_t gfp)
{
struct rxrpc_net *rxnet = conn->params.local->rxnet;
- int id;
+ unsigned long id;
+ int ret;
_enter("");
idr_preload(gfp);
spin_lock(&rxrpc_conn_id_lock);
- id = idr_alloc_cyclic(&rxrpc_client_conn_ids, conn,
- 1, 0x40000000, GFP_NOWAIT);
- if (id < 0)
+ ret = idr_alloc_cyclic(&rxrpc_client_conn_ids, conn, &id,
+ 1, 0x40000000, GFP_NOWAIT);
+ if (ret)
goto error;
spin_unlock(&rxrpc_conn_id_lock);
@@ -130,8 +131,8 @@ static int rxrpc_get_client_connection_id(struct rxrpc_connection *conn,
error:
spin_unlock(&rxrpc_conn_id_lock);
idr_preload_end();
- _leave(" = %d", id);
- return id;
+ _leave(" = %d", ret);
+ return ret;
}
/*
@@ -153,7 +154,7 @@ static void rxrpc_put_client_connection_id(struct rxrpc_connection *conn)
void rxrpc_destroy_client_conn_ids(void)
{
struct rxrpc_connection *conn;
- int id;
+ unsigned long id;
if (!idr_is_empty(&rxrpc_client_conn_ids)) {
idr_for_each_entry(&rxrpc_client_conn_ids, conn, id) {
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index dfb9651..c3086c1 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -1613,6 +1613,7 @@ int sctp_assoc_lookup_laddr(struct sctp_association *asoc,
int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp)
{
bool preload = gfpflags_allow_blocking(gfp);
+ unsigned long idr_index;
int ret;
/* If the id is already assigned, keep it. */
@@ -1623,14 +1624,15 @@ int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp)
idr_preload(gfp);
spin_lock_bh(&sctp_assocs_id_lock);
/* 0 is not a valid assoc_id, must be >= 1 */
- ret = idr_alloc_cyclic(&sctp_assocs_id, asoc, 1, 0, GFP_NOWAIT);
+ ret = idr_alloc_cyclic(&sctp_assocs_id, asoc, &idr_index, 1, 0,
+ GFP_NOWAIT);
spin_unlock_bh(&sctp_assocs_id_lock);
if (preload)
idr_preload_end();
- if (ret < 0)
+ if (ret)
return ret;
- asoc->assoc_id = (sctp_assoc_t)ret;
+ asoc->assoc_id = (sctp_assoc_t)idr_index;
return 0;
}
diff --git a/net/tipc/server.c b/net/tipc/server.c
index 3cd6402..9c83545 100644
--- a/net/tipc/server.c
+++ b/net/tipc/server.c
@@ -216,6 +216,7 @@ static void tipc_close_conn(struct tipc_conn *con)
static struct tipc_conn *tipc_alloc_conn(struct tipc_server *s)
{
struct tipc_conn *con;
+ unsigned long idr_index;
int ret;
con = kzalloc(sizeof(struct tipc_conn), GFP_ATOMIC);
@@ -229,13 +230,13 @@ static struct tipc_conn *tipc_alloc_conn(struct tipc_server *s)
INIT_WORK(&con->rwork, tipc_recv_work);
spin_lock_bh(&s->idr_lock);
- ret = idr_alloc(&s->conn_idr, con, 0, 0, GFP_ATOMIC);
- if (ret < 0) {
+ ret = idr_alloc(&s->conn_idr, con, &idr_index, 0, 0, GFP_ATOMIC);
+ if (ret) {
kfree(con);
spin_unlock_bh(&s->idr_lock);
return ERR_PTR(-ENOMEM);
}
- con->conid = ret;
+ con->conid = idr_index;
s->idr_in_use++;
spin_unlock_bh(&s->idr_lock);
--
1.8.3.1
^ permalink raw reply related
* [patch net-next repost 0/3] net/sched: Improve getting objects by indexes
From: Chris Mi @ 2017-08-16 8:14 UTC (permalink / raw)
To: netdev; +Cc: jhs, xiyou.wangcong, jiri, davem, mawilcox
Using current TC code, it is very slow to insert a lot of rules.
In order to improve the rules update rate in TC,
we introduced the following two changes:
1) changed cls_flower to use IDR to manage the filters.
2) changed all act_xxx modules to use IDR instead of
a small hash table
But IDR has a limitation that it uses int. TC handle uses u32.
To make sure there is no regression, we also changed IDR to use
unsigned long. All clients of IDR are changed to use new IDR API.
Chris Mi (3):
idr: Use unsigned long instead of int
net/sched: Change cls_flower to use IDR
net/sched: Change act_api and act_xxx modules to use IDR
block/bsg.c | 8 +-
block/genhd.c | 12 +-
drivers/atm/nicstar.c | 11 +-
drivers/block/drbd/drbd_main.c | 31 +--
drivers/block/drbd/drbd_nl.c | 22 ++-
drivers/block/drbd/drbd_proc.c | 3 +-
drivers/block/drbd/drbd_receiver.c | 15 +-
drivers/block/drbd/drbd_state.c | 34 ++--
drivers/block/drbd/drbd_worker.c | 6 +-
drivers/block/loop.c | 17 +-
drivers/block/nbd.c | 20 +-
drivers/block/zram/zram_drv.c | 9 +-
drivers/char/tpm/tpm-chip.c | 10 +-
drivers/char/tpm/tpm.h | 2 +-
drivers/dca/dca-sysfs.c | 9 +-
drivers/firewire/core-cdev.c | 18 +-
drivers/firewire/core-device.c | 15 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 8 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 9 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 6 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 2 +-
drivers/gpu/drm/drm_auth.c | 9 +-
drivers/gpu/drm/drm_connector.c | 10 +-
drivers/gpu/drm/drm_context.c | 20 +-
drivers/gpu/drm/drm_dp_aux_dev.c | 11 +-
drivers/gpu/drm/drm_drv.c | 6 +-
drivers/gpu/drm/drm_gem.c | 19 +-
drivers/gpu/drm/drm_info.c | 2 +-
drivers/gpu/drm/drm_mode_object.c | 11 +-
drivers/gpu/drm/drm_syncobj.c | 18 +-
drivers/gpu/drm/exynos/exynos_drm_ipp.c | 25 ++-
drivers/gpu/drm/i915/gvt/display.c | 2 +-
drivers/gpu/drm/i915/gvt/kvmgt.c | 2 +-
drivers/gpu/drm/i915/gvt/vgpu.c | 9 +-
drivers/gpu/drm/i915/i915_debugfs.c | 6 +-
drivers/gpu/drm/i915/i915_gem_context.c | 9 +-
drivers/gpu/drm/qxl/qxl_cmd.c | 8 +-
drivers/gpu/drm/qxl/qxl_release.c | 14 +-
drivers/gpu/drm/sis/sis_mm.c | 8 +-
drivers/gpu/drm/tegra/drm.c | 10 +-
drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c | 3 +-
drivers/gpu/drm/vgem/vgem_fence.c | 12 +-
drivers/gpu/drm/via/via_mm.c | 8 +-
drivers/gpu/drm/virtio/virtgpu_kms.c | 5 +-
drivers/gpu/drm/virtio/virtgpu_vq.c | 5 +-
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 9 +-
drivers/i2c/i2c-core-base.c | 19 +-
drivers/infiniband/core/cm.c | 8 +-
drivers/infiniband/core/cma.c | 12 +-
drivers/infiniband/core/rdma_core.c | 9 +-
drivers/infiniband/core/sa_query.c | 23 +--
drivers/infiniband/core/ucm.c | 7 +-
drivers/infiniband/core/ucma.c | 14 +-
drivers/infiniband/hw/cxgb3/iwch.c | 4 +-
drivers/infiniband/hw/cxgb3/iwch.h | 4 +-
drivers/infiniband/hw/cxgb4/device.c | 18 +-
drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 4 +-
drivers/infiniband/hw/hfi1/init.c | 9 +-
drivers/infiniband/hw/hfi1/vnic_main.c | 6 +-
drivers/infiniband/hw/mlx4/cm.c | 13 +-
drivers/infiniband/hw/ocrdma/ocrdma_main.c | 7 +-
drivers/infiniband/hw/qib/qib_init.c | 9 +-
drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c | 10 +-
drivers/iommu/intel-svm.c | 9 +-
drivers/md/dm.c | 13 +-
drivers/memstick/core/memstick.c | 10 +-
drivers/memstick/core/ms_block.c | 9 +-
drivers/memstick/core/mspro_block.c | 12 +-
drivers/mfd/rtsx_pcr.c | 9 +-
drivers/misc/c2port/core.c | 7 +-
drivers/misc/cxl/context.c | 8 +-
drivers/misc/cxl/main.c | 15 +-
drivers/misc/mei/main.c | 8 +-
drivers/misc/mic/scif/scif_api.c | 11 +-
drivers/misc/mic/scif/scif_ports.c | 18 +-
drivers/misc/tifm_core.c | 9 +-
drivers/mtd/mtdcore.c | 9 +-
drivers/mtd/mtdcore.h | 2 +-
drivers/mtd/ubi/block.c | 7 +-
drivers/net/ppp/ppp_generic.c | 27 +--
drivers/net/tap.c | 10 +-
drivers/net/wireless/ath/ath10k/htt.h | 3 +-
drivers/net/wireless/ath/ath10k/htt_tx.c | 22 ++-
drivers/net/wireless/ath/ath10k/mac.c | 2 +-
drivers/net/wireless/marvell/mwifiex/main.c | 13 +-
drivers/net/wireless/marvell/mwifiex/wmm.c | 2 +-
drivers/of/overlay.c | 15 +-
drivers/of/unittest.c | 25 ++-
drivers/power/supply/bq2415x_charger.c | 16 +-
drivers/power/supply/bq27xxx_battery_i2c.c | 15 +-
drivers/power/supply/ds2782_battery.c | 9 +-
drivers/powercap/powercap_sys.c | 8 +-
drivers/pps/pps.c | 10 +-
drivers/rapidio/rio_cm.c | 17 +-
drivers/remoteproc/remoteproc_core.c | 8 +-
drivers/rpmsg/virtio_rpmsg_bus.c | 8 +-
drivers/scsi/bfa/bfad_im.c | 8 +-
drivers/scsi/ch.c | 8 +-
drivers/scsi/lpfc/lpfc_crtn.h | 2 +-
drivers/scsi/lpfc/lpfc_init.c | 11 +-
drivers/scsi/lpfc/lpfc_vport.c | 8 +-
drivers/scsi/sg.c | 10 +-
drivers/scsi/st.c | 8 +-
drivers/staging/greybus/uart.c | 22 +--
drivers/staging/unisys/visorhba/visorhba_main.c | 7 +-
drivers/target/iscsi/iscsi_target.c | 7 +-
drivers/target/iscsi/iscsi_target_login.c | 9 +-
drivers/target/target_core_device.c | 9 +-
drivers/target/target_core_user.c | 13 +-
drivers/tee/tee_shm.c | 8 +-
drivers/uio/uio.c | 9 +-
drivers/usb/class/cdc-acm.c | 24 +--
drivers/usb/core/devices.c | 2 +-
drivers/usb/core/hcd.c | 7 +-
drivers/usb/mon/mon_main.c | 3 +-
drivers/usb/serial/usb-serial.c | 11 +-
drivers/vfio/vfio.c | 15 +-
fs/dlm/lock.c | 9 +-
fs/dlm/lockspace.c | 6 +-
fs/dlm/recover.c | 10 +-
fs/nfs/nfs4client.c | 9 +-
fs/nfsd/nfs4state.c | 8 +-
fs/notify/inotify/inotify_fsnotify.c | 4 +-
fs/notify/inotify/inotify_user.c | 9 +-
fs/ocfs2/cluster/tcp.c | 10 +-
include/linux/idr.h | 26 +--
include/linux/of.h | 4 +-
include/linux/radix-tree.h | 2 +-
include/net/9p/9p.h | 2 +-
include/net/act_api.h | 76 +++-----
ipc/msg.c | 2 +-
ipc/sem.c | 2 +-
ipc/shm.c | 4 +-
ipc/util.c | 17 +-
kernel/bpf/syscall.c | 20 +-
kernel/cgroup/cgroup.c | 57 +++---
kernel/events/core.c | 10 +-
kernel/workqueue.c | 15 +-
lib/idr.c | 38 ++--
lib/radix-tree.c | 5 +-
mm/memcontrol.c | 11 +-
net/9p/client.c | 17 +-
net/9p/util.c | 14 +-
net/core/net_namespace.c | 23 ++-
net/mac80211/cfg.c | 23 +--
net/mac80211/iface.c | 3 +-
net/mac80211/main.c | 2 +-
net/mac80211/tx.c | 7 +-
net/mac80211/util.c | 3 +-
net/netlink/genetlink.c | 18 +-
net/qrtr/qrtr.c | 21 +-
net/rxrpc/conn_client.c | 15 +-
net/sched/act_api.c | 249 +++++++++++-------------
net/sched/act_bpf.c | 17 +-
net/sched/act_connmark.c | 16 +-
net/sched/act_csum.c | 16 +-
net/sched/act_gact.c | 16 +-
net/sched/act_ife.c | 20 +-
net/sched/act_ipt.c | 26 ++-
net/sched/act_mirred.c | 19 +-
net/sched/act_nat.c | 16 +-
net/sched/act_pedit.c | 18 +-
net/sched/act_police.c | 18 +-
net/sched/act_sample.c | 17 +-
net/sched/act_simple.c | 20 +-
net/sched/act_skbedit.c | 18 +-
net/sched/act_skbmod.c | 18 +-
net/sched/act_tunnel_key.c | 20 +-
net/sched/act_vlan.c | 22 +--
net/sched/cls_flower.c | 55 +++---
net/sctp/associola.c | 8 +-
net/tipc/server.c | 7 +-
172 files changed, 1256 insertions(+), 1113 deletions(-)
--
1.8.3.1
^ permalink raw reply
* Re: [PATCH] net: igmp: Use ingress interface rather than vrf device
From: Nikolay Aleksandrov @ 2017-08-16 7:57 UTC (permalink / raw)
To: David Ahern, netdev
In-Reply-To: <1502847522-13020-1-git-send-email-dsahern@gmail.com>
On 16/08/17 04:38, David Ahern wrote:
> Anuradha reported that statically added groups for interfaces enslaved
> to a VRF device were not persisting. The problem is that igmp queries
> and reports need to use the data in the in_dev for the real ingress
> device rather than the VRF device. Update igmp_rcv accordingly.
>
> Fixes: e58e41596811 ("net: Enable support for VRF with ipv4 multicast")
> Reported-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
> Signed-off-by: David Ahern <dsahern@gmail.com>
> ---
> net/ipv4/igmp.c | 10 +++++++++-
> 1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
> index 9f86b5133605..ab183af0b5b6 100644
> --- a/net/ipv4/igmp.c
> +++ b/net/ipv4/igmp.c
> @@ -1007,10 +1007,18 @@ int igmp_rcv(struct sk_buff *skb)
> {
> /* This basically follows the spec line by line -- see RFC1112 */
> struct igmphdr *ih;
> - struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
> + struct net_device *dev = skb->dev;
> + struct in_device *in_dev;
> int len = skb->len;
> bool dropped = true;
>
> + if (netif_is_l3_master(dev)) {
> + dev = dev_get_by_index_rcu(dev_net(dev), IPCB(skb)->iif);
> + if (!dev)
> + goto drop;
> + }
> +
> + in_dev = __in_dev_get_rcu(dev);
> if (!in_dev)
> goto drop;
>
>
Reviewed-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
^ permalink raw reply
* DSA support for Micrel KSZ8895
From: Pavel Machek @ 2017-08-16 7:55 UTC (permalink / raw)
To: andrew, vivien.didelot, f.fainelli, netdev, linux-kernel,
Tristram.Ha, Woojung.Huh
[-- Attachment #1: Type: text/plain, Size: 653 bytes --]
Hi!
I've got hardware with KSZ8895, and I'd like to use switch ports as
separate ethernet cards. I believe that means DSA support.
And there are even patches available from microchip... unfortunately
they are in strange form and for v3.18.
http://www.microchip.com/SWLibraryWeb/product.aspx?product=KSZ8895%20Software%20Linux%203.18
Is there newer version of the driver available somewhere? Is the
driver good starting point, or should I start with something else?
Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply
* Re: [patch net-next 0/3] net/sched: Improve getting objects by indexes
From: Christian König @ 2017-08-16 7:49 UTC (permalink / raw)
To: Chris Mi, netdev-u79uwXL29TY76Z2rM5mHXA
Cc: lucho-OnYtXJJ0/fesTnJN9+BGXg,
sergey.senozhatsky.work-Re5JQEeQqe8AvxtiuMwx3w,
snitzer-H+wXaHxf7aLQT0dZR+AlfA, wsa-z923LK4zBo2bacvFa/9K2g,
markb-VPRAkNaXOzVWk0Htik3J/w, tom.leiming-Re5JQEeQqe8AvxtiuMwx3w,
stefanr-MtYdepGKPcBMYopoZt5u/LNAH6kLmebB,
zhi.a.wang-ral2JQCrhuEAvxtiuMwx3w, nsekhar-l0cyMroinI0,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
bfields-uC3wQj2KruNg9hUCZPvPmw, linux-sctp-u79uwXL29TY76Z2rM5mHXA,
paulus-eUNUBHrolfbYtjvyW6yDsg, jinpu.wang-EIkl63zCoXaH+58JC4qpiA,
pshelar-LZ6Gd1LRuIk, sumit.semwal-QSEj5FYQhm4dnm+yROfE0A,
AlexBin.Xie-5C7GfCeVMHo, david1.zhou-5C7GfCeVMHo,
linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
maximlevitsky-Re5JQEeQqe8AvxtiuMwx3w,
sudarsana.kalluru-h88ZbnxC6KDQT0dZR+AlfA,
marek.vasut-Re5JQEeQqe8AvxtiuMwx3w,
linux-atm-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
dtwlin-Re5JQEeQqe8AvxtiuMwx3w, michel.daenzer-5C7GfCeVMHo,
dledford-H+wXaHxf7aLQT0dZR+AlfA,
tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz,
longman-H+wXaHxf7aLQT0dZR+AlfA,
niranjana.vishwanathapura-ral2JQCrhuEAvxtiuMwx3w,
philipp.reisner-63ez5xqkn6DQT0dZR+AlfA,
shli-DgEjT+Ai2ygdnm+yROfE0A, linux-0h96xk9xTtrk1uMJSBkQmQ,
ohad-Ix1uc/W3ht7QT0dZR+AlfA, pmladek-IBi9RG/b67k,
dick.kennedy-dY08KVG/lbpWk0Htik3J/w, linu
In-Reply-To: <1502849538-14284-1-git-send-email-chrism-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Am 16.08.2017 um 04:12 schrieb Chris Mi:
> Using current TC code, it is very slow to insert a lot of rules.
>
> In order to improve the rules update rate in TC,
> we introduced the following two changes:
> 1) changed cls_flower to use IDR to manage the filters.
> 2) changed all act_xxx modules to use IDR instead of
> a small hash table
>
> But IDR has a limitation that it uses int. TC handle uses u32.
> To make sure there is no regression, we also changed IDR to use
> unsigned long. All clients of IDR are changed to use new IDR API.
WOW, wait a second. The idr change is touching a lot of drivers and to
be honest doesn't looks correct at all.
Just look at the first chunk of your modification:
> @@ -998,8 +999,9 @@ int bsg_register_queue(struct request_queue *q, struct device *parent,
>
> mutex_lock(&bsg_mutex);
>
> - ret = idr_alloc(&bsg_minor_idr, bcd, 0, BSG_MAX_DEVS, GFP_KERNEL);
> - if (ret < 0) {
> + ret = idr_alloc(&bsg_minor_idr, bcd, &idr_index, 0, BSG_MAX_DEVS,
> + GFP_KERNEL);
> + if (ret) {
> if (ret == -ENOSPC) {
> printk(KERN_ERR "bsg: too many bsg devices\n");
> ret = -EINVAL;
The condition "if (ret)" will now always be true after the first
allocation and so we always run into the error handling after that.
I've never read the bsg code before, but that's certainly not correct.
And that incorrect pattern repeats over and over again in this code.
Apart from that why the heck do you want to allocate more than 1<<31
handles?
Regards,
Christian.
>
> Chris Mi (3):
> idr: Use unsigned long instead of int
> net/sched: Change cls_flower to use IDR
> net/sched: Change act_api and act_xxx modules to use IDR
>
> block/bsg.c | 8 +-
> block/genhd.c | 12 +-
> drivers/atm/nicstar.c | 11 +-
> drivers/block/drbd/drbd_main.c | 31 +--
> drivers/block/drbd/drbd_nl.c | 22 ++-
> drivers/block/drbd/drbd_proc.c | 3 +-
> drivers/block/drbd/drbd_receiver.c | 15 +-
> drivers/block/drbd/drbd_state.c | 34 ++--
> drivers/block/drbd/drbd_worker.c | 6 +-
> drivers/block/loop.c | 17 +-
> drivers/block/nbd.c | 20 +-
> drivers/block/zram/zram_drv.c | 9 +-
> drivers/char/tpm/tpm-chip.c | 10 +-
> drivers/char/tpm/tpm.h | 2 +-
> drivers/dca/dca-sysfs.c | 9 +-
> drivers/firewire/core-cdev.c | 18 +-
> drivers/firewire/core-device.c | 15 +-
> drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 8 +-
> drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 9 +-
> drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 6 +-
> drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 2 +-
> drivers/gpu/drm/drm_auth.c | 9 +-
> drivers/gpu/drm/drm_connector.c | 10 +-
> drivers/gpu/drm/drm_context.c | 20 +-
> drivers/gpu/drm/drm_dp_aux_dev.c | 11 +-
> drivers/gpu/drm/drm_drv.c | 6 +-
> drivers/gpu/drm/drm_gem.c | 19 +-
> drivers/gpu/drm/drm_info.c | 2 +-
> drivers/gpu/drm/drm_mode_object.c | 11 +-
> drivers/gpu/drm/drm_syncobj.c | 18 +-
> drivers/gpu/drm/exynos/exynos_drm_ipp.c | 25 ++-
> drivers/gpu/drm/i915/gvt/display.c | 2 +-
> drivers/gpu/drm/i915/gvt/kvmgt.c | 2 +-
> drivers/gpu/drm/i915/gvt/vgpu.c | 9 +-
> drivers/gpu/drm/i915/i915_debugfs.c | 6 +-
> drivers/gpu/drm/i915/i915_gem_context.c | 9 +-
> drivers/gpu/drm/qxl/qxl_cmd.c | 8 +-
> drivers/gpu/drm/qxl/qxl_release.c | 14 +-
> drivers/gpu/drm/sis/sis_mm.c | 8 +-
> drivers/gpu/drm/tegra/drm.c | 10 +-
> drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c | 3 +-
> drivers/gpu/drm/vgem/vgem_fence.c | 12 +-
> drivers/gpu/drm/via/via_mm.c | 8 +-
> drivers/gpu/drm/virtio/virtgpu_kms.c | 5 +-
> drivers/gpu/drm/virtio/virtgpu_vq.c | 5 +-
> drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 9 +-
> drivers/i2c/i2c-core-base.c | 19 +-
> drivers/infiniband/core/cm.c | 8 +-
> drivers/infiniband/core/cma.c | 12 +-
> drivers/infiniband/core/rdma_core.c | 9 +-
> drivers/infiniband/core/sa_query.c | 23 +--
> drivers/infiniband/core/ucm.c | 7 +-
> drivers/infiniband/core/ucma.c | 14 +-
> drivers/infiniband/hw/cxgb3/iwch.c | 4 +-
> drivers/infiniband/hw/cxgb3/iwch.h | 4 +-
> drivers/infiniband/hw/cxgb4/device.c | 18 +-
> drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 4 +-
> drivers/infiniband/hw/hfi1/init.c | 9 +-
> drivers/infiniband/hw/hfi1/vnic_main.c | 6 +-
> drivers/infiniband/hw/mlx4/cm.c | 13 +-
> drivers/infiniband/hw/ocrdma/ocrdma_main.c | 7 +-
> drivers/infiniband/hw/qib/qib_init.c | 9 +-
> drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c | 10 +-
> drivers/iommu/intel-svm.c | 9 +-
> drivers/md/dm.c | 13 +-
> drivers/memstick/core/memstick.c | 10 +-
> drivers/memstick/core/ms_block.c | 9 +-
> drivers/memstick/core/mspro_block.c | 12 +-
> drivers/mfd/rtsx_pcr.c | 9 +-
> drivers/misc/c2port/core.c | 7 +-
> drivers/misc/cxl/context.c | 8 +-
> drivers/misc/cxl/main.c | 15 +-
> drivers/misc/mei/main.c | 8 +-
> drivers/misc/mic/scif/scif_api.c | 11 +-
> drivers/misc/mic/scif/scif_ports.c | 18 +-
> drivers/misc/tifm_core.c | 9 +-
> drivers/mtd/mtdcore.c | 9 +-
> drivers/mtd/mtdcore.h | 2 +-
> drivers/mtd/ubi/block.c | 7 +-
> drivers/net/ppp/ppp_generic.c | 27 +--
> drivers/net/tap.c | 10 +-
> drivers/net/wireless/ath/ath10k/htt.h | 3 +-
> drivers/net/wireless/ath/ath10k/htt_tx.c | 22 ++-
> drivers/net/wireless/ath/ath10k/mac.c | 2 +-
> drivers/net/wireless/marvell/mwifiex/main.c | 13 +-
> drivers/net/wireless/marvell/mwifiex/wmm.c | 2 +-
> drivers/of/overlay.c | 15 +-
> drivers/of/unittest.c | 25 ++-
> drivers/power/supply/bq2415x_charger.c | 16 +-
> drivers/power/supply/bq27xxx_battery_i2c.c | 15 +-
> drivers/power/supply/ds2782_battery.c | 9 +-
> drivers/powercap/powercap_sys.c | 8 +-
> drivers/pps/pps.c | 10 +-
> drivers/rapidio/rio_cm.c | 17 +-
> drivers/remoteproc/remoteproc_core.c | 8 +-
> drivers/rpmsg/virtio_rpmsg_bus.c | 8 +-
> drivers/scsi/bfa/bfad_im.c | 8 +-
> drivers/scsi/ch.c | 8 +-
> drivers/scsi/lpfc/lpfc_crtn.h | 2 +-
> drivers/scsi/lpfc/lpfc_init.c | 11 +-
> drivers/scsi/lpfc/lpfc_vport.c | 8 +-
> drivers/scsi/sg.c | 10 +-
> drivers/scsi/st.c | 8 +-
> drivers/staging/greybus/uart.c | 22 +--
> drivers/staging/unisys/visorhba/visorhba_main.c | 7 +-
> drivers/target/iscsi/iscsi_target.c | 7 +-
> drivers/target/iscsi/iscsi_target_login.c | 9 +-
> drivers/target/target_core_device.c | 9 +-
> drivers/target/target_core_user.c | 13 +-
> drivers/tee/tee_shm.c | 8 +-
> drivers/uio/uio.c | 9 +-
> drivers/usb/class/cdc-acm.c | 24 +--
> drivers/usb/core/devices.c | 2 +-
> drivers/usb/core/hcd.c | 7 +-
> drivers/usb/mon/mon_main.c | 3 +-
> drivers/usb/serial/usb-serial.c | 11 +-
> drivers/vfio/vfio.c | 15 +-
> fs/dlm/lock.c | 9 +-
> fs/dlm/lockspace.c | 6 +-
> fs/dlm/recover.c | 10 +-
> fs/nfs/nfs4client.c | 9 +-
> fs/nfsd/nfs4state.c | 8 +-
> fs/notify/inotify/inotify_fsnotify.c | 4 +-
> fs/notify/inotify/inotify_user.c | 9 +-
> fs/ocfs2/cluster/tcp.c | 10 +-
> include/linux/idr.h | 26 +--
> include/linux/of.h | 4 +-
> include/linux/radix-tree.h | 2 +-
> include/net/9p/9p.h | 2 +-
> include/net/act_api.h | 76 +++-----
> ipc/msg.c | 2 +-
> ipc/sem.c | 2 +-
> ipc/shm.c | 4 +-
> ipc/util.c | 17 +-
> kernel/bpf/syscall.c | 20 +-
> kernel/cgroup/cgroup.c | 57 +++---
> kernel/events/core.c | 10 +-
> kernel/workqueue.c | 15 +-
> lib/idr.c | 38 ++--
> lib/radix-tree.c | 5 +-
> mm/memcontrol.c | 11 +-
> net/9p/client.c | 17 +-
> net/9p/util.c | 14 +-
> net/core/net_namespace.c | 23 ++-
> net/mac80211/cfg.c | 23 +--
> net/mac80211/iface.c | 3 +-
> net/mac80211/main.c | 2 +-
> net/mac80211/tx.c | 7 +-
> net/mac80211/util.c | 3 +-
> net/netlink/genetlink.c | 18 +-
> net/qrtr/qrtr.c | 21 +-
> net/rxrpc/conn_client.c | 15 +-
> net/sched/act_api.c | 249 +++++++++++-------------
> net/sched/act_bpf.c | 17 +-
> net/sched/act_connmark.c | 16 +-
> net/sched/act_csum.c | 16 +-
> net/sched/act_gact.c | 16 +-
> net/sched/act_ife.c | 20 +-
> net/sched/act_ipt.c | 26 ++-
> net/sched/act_mirred.c | 19 +-
> net/sched/act_nat.c | 16 +-
> net/sched/act_pedit.c | 18 +-
> net/sched/act_police.c | 18 +-
> net/sched/act_sample.c | 17 +-
> net/sched/act_simple.c | 20 +-
> net/sched/act_skbedit.c | 18 +-
> net/sched/act_skbmod.c | 18 +-
> net/sched/act_tunnel_key.c | 20 +-
> net/sched/act_vlan.c | 22 +--
> net/sched/cls_flower.c | 55 +++---
> net/sctp/associola.c | 8 +-
> net/tipc/server.c | 7 +-
> 172 files changed, 1256 insertions(+), 1113 deletions(-)
>
^ permalink raw reply
* Re: 100% CPU load when generating traffic to destination network that nexthop is not reachable
From: Julian Anastasov @ 2017-08-16 7:42 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Paweł Staszewski, Linux Kernel Network Developers
In-Reply-To: <1502831185.4936.87.camel@edumazet-glaptop3.roam.corp.google.com>
Hello,
On Tue, 15 Aug 2017, Eric Dumazet wrote:
> It must be possible to add a fast path without locks.
>
> (say if jiffies has not changed before last state change)
New day - new idea. Something like this? But it
has bug: without checking neigh->dead under lock we don't
have the right to access neigh->parms, it can be destroyed
immediately by neigh_release->neigh_destroy->neigh_parms_put->
neigh_parms_destroy->kfree. Not sure, may be kfree_rcu can help
for this...
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 9816df2..f52763c 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -428,10 +428,10 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
{
unsigned long now = jiffies;
- if (neigh->used != now)
- neigh->used = now;
if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE)))
return __neigh_event_send(neigh, skb);
+ if (neigh->used != now)
+ neigh->used = now;
return 0;
}
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 16a1a4c..52a8718 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -991,8 +991,18 @@ static void neigh_timer_handler(unsigned long arg)
int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
{
- int rc;
bool immediate_probe = false;
+ unsigned long now = jiffies;
+ int rc;
+
+ if (neigh->used != now) {
+ neigh->used = now;
+ } else if (neigh->nud_state == NUD_INCOMPLETE &&
+ (!skb || neigh->arp_queue_len_bytes + skb->truesize >
+ NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES))) {
+ kfree_skb(skb);
+ return 1;
+ }
write_lock_bh(&neigh->lock);
@@ -1005,7 +1015,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
NEIGH_VAR(neigh->parms, APP_PROBES)) {
- unsigned long next, now = jiffies;
+ unsigned long next;
atomic_set(&neigh->probes,
NEIGH_VAR(neigh->parms, UCAST_PROBES));
Regards
^ permalink raw reply related
* [PATCH net-next 2/2] nfp: process MTU updates from firmware flower app
From: Simon Horman @ 2017-08-16 7:37 UTC (permalink / raw)
To: David Miller, Jakub Kicinski; +Cc: netdev, oss-drivers, Simon Horman
In-Reply-To: <1502869064-25842-1-git-send-email-simon.horman@netronome.com>
Now that control message processing occurs in a workqueue rather than a BH
handler MTU updates received from the firmware may be safely processed.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
drivers/net/ethernet/netronome/nfp/flower/cmsg.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c
index 6c8c22491fe7..806924b82adc 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c
@@ -150,10 +150,17 @@ nfp_flower_cmsg_portmod_rx(struct nfp_app *app, struct sk_buff *skb)
return;
}
- if (link)
+ if (link) {
+ u16 mtu = be16_to_cpu(msg->mtu);
+
netif_carrier_on(netdev);
- else
+
+ /* An MTU of 0 from the firmware should be ignored */
+ if (mtu)
+ dev_set_mtu(netdev, mtu);
+ } else {
netif_carrier_off(netdev);
+ }
rcu_read_unlock();
}
--
2.1.4
^ permalink raw reply related
* [PATCH net-next 1/2] nfp: process control messages in workqueue in flower app
From: Simon Horman @ 2017-08-16 7:37 UTC (permalink / raw)
To: David Miller, Jakub Kicinski; +Cc: netdev, oss-drivers, Simon Horman
In-Reply-To: <1502869064-25842-1-git-send-email-simon.horman@netronome.com>
Processing of control messages is not time-critical and future processing
of some messages will require taking the RTNL which is not possible
in a BH handler. It seems simplest to move all control message processing
to a workqueue.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
drivers/net/ethernet/netronome/nfp/flower/cmsg.c | 24 +++++++++++++++++++++++-
drivers/net/ethernet/netronome/nfp/flower/cmsg.h | 1 +
drivers/net/ethernet/netronome/nfp/flower/main.c | 14 ++++++++++++--
drivers/net/ethernet/netronome/nfp/flower/main.h | 5 +++++
4 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c
index aa46b23cdfb1..6c8c22491fe7 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c
@@ -34,10 +34,12 @@
#include <linux/bitfield.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
+#include <linux/workqueue.h>
#include <net/dst_metadata.h>
#include "main.h"
#include "../nfpcore/nfp_cpp.h"
+#include "../nfp_net.h"
#include "../nfp_net_repr.h"
#include "./cmsg.h"
@@ -155,7 +157,8 @@ nfp_flower_cmsg_portmod_rx(struct nfp_app *app, struct sk_buff *skb)
rcu_read_unlock();
}
-void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb)
+static void
+nfp_flower_cmsg_process_one_rx(struct nfp_app *app, struct sk_buff *skb)
{
struct nfp_flower_cmsg_hdr *cmsg_hdr;
enum nfp_flower_cmsg_type_port type;
@@ -184,3 +187,22 @@ void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb)
out:
dev_kfree_skb_any(skb);
}
+
+void nfp_flower_cmsg_process_rx(struct work_struct *work)
+{
+ struct nfp_flower_priv *priv;
+ struct sk_buff *skb;
+
+ priv = container_of(work, struct nfp_flower_priv, cmsg_work);
+
+ while ((skb = skb_dequeue(&priv->cmsg_skbs)))
+ nfp_flower_cmsg_process_one_rx(priv->nn->app, skb);
+}
+
+void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb)
+{
+ struct nfp_flower_priv *priv = app->priv;
+
+ skb_queue_tail(&priv->cmsg_skbs, skb);
+ schedule_work(&priv->cmsg_work);
+}
diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h
index aa92a8711a02..a2ec60344236 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h
+++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h
@@ -330,6 +330,7 @@ nfp_flower_cmsg_mac_repr_add(struct sk_buff *skb, unsigned int idx,
unsigned int nbi, unsigned int nbi_port,
unsigned int phys_port);
int nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok);
+void nfp_flower_cmsg_process_rx(struct work_struct *work);
void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb);
struct sk_buff *
nfp_flower_cmsg_alloc(struct nfp_app *app, unsigned int size,
diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c
index b905454b30ca..3088e959f2a3 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.c
@@ -332,6 +332,7 @@ static int nfp_flower_vnic_init(struct nfp_app *app, struct nfp_net *nn,
static int nfp_flower_init(struct nfp_app *app)
{
const struct nfp_pf *pf = app->pf;
+ struct nfp_flower_priv *app_priv;
u64 version;
int err;
@@ -362,10 +363,14 @@ static int nfp_flower_init(struct nfp_app *app)
return -EINVAL;
}
- app->priv = vzalloc(sizeof(struct nfp_flower_priv));
- if (!app->priv)
+ app_priv = vzalloc(sizeof(struct nfp_flower_priv));
+ if (!app_priv)
return -ENOMEM;
+ app->priv = app_priv;
+ skb_queue_head_init(&app_priv->cmsg_skbs);
+ INIT_WORK(&app_priv->cmsg_work, nfp_flower_cmsg_process_rx);
+
err = nfp_flower_metadata_init(app);
if (err)
goto err_free_app_priv;
@@ -379,6 +384,11 @@ static int nfp_flower_init(struct nfp_app *app)
static void nfp_flower_clean(struct nfp_app *app)
{
+ struct nfp_flower_priv *app_priv = app->priv;
+
+ skb_queue_purge(&app_priv->cmsg_skbs);
+ flush_work(&app_priv->cmsg_work);
+
nfp_flower_metadata_cleanup(app);
vfree(app->priv);
app->priv = NULL;
diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h
index 71e4f4f4e9ba..b7043ca9b9fc 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.h
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.h
@@ -39,6 +39,7 @@
#include <linux/time64.h>
#include <linux/types.h>
#include <net/pkt_cls.h>
+#include <linux/workqueue.h>
struct net_device;
struct nfp_app;
@@ -78,6 +79,8 @@ struct nfp_fl_stats_id {
* @mask_ids: List of free mask ids
* @mask_table: Hash table used to store masks
* @flow_table: Hash table used to store flower rules
+ * @cmsg_work: Workqueue for control messages processing
+ * @cmsg_skbs: List of skbs for control message processing
*/
struct nfp_flower_priv {
struct nfp_net *nn;
@@ -87,6 +90,8 @@ struct nfp_flower_priv {
struct nfp_fl_mask_id mask_ids;
DECLARE_HASHTABLE(mask_table, NFP_FLOWER_MASK_HASH_BITS);
DECLARE_HASHTABLE(flow_table, NFP_FLOWER_HASH_BITS);
+ struct work_struct cmsg_work;
+ struct sk_buff_head cmsg_skbs;
};
struct nfp_fl_key_ls {
--
2.1.4
^ permalink raw reply related
* [PATCH net-next 0/2] nfp: process MTU updates from firmware flower app
From: Simon Horman @ 2017-08-16 7:37 UTC (permalink / raw)
To: David Miller, Jakub Kicinski; +Cc: netdev, oss-drivers, Simon Horman
The first patch of this series moves processing of control messages from a
BH handler to a workqueue. That change makes it safe to process MTU
updates from the firmware which is added by the second patch of this
series.
Simon Horman (2):
nfp: process control messages in workqueue in flower app
nfp: process MTU updates from firmware flower app
drivers/net/ethernet/netronome/nfp/flower/cmsg.c | 35 ++++++++++++++++++++++--
drivers/net/ethernet/netronome/nfp/flower/cmsg.h | 1 +
drivers/net/ethernet/netronome/nfp/flower/main.c | 14 ++++++++--
drivers/net/ethernet/netronome/nfp/flower/main.h | 5 ++++
4 files changed, 50 insertions(+), 5 deletions(-)
--
2.1.4
^ permalink raw reply
* [net-next PATCH] bpf: devmap: remove unnecessary value size check
From: John Fastabend @ 2017-08-16 6:35 UTC (permalink / raw)
To: davem; +Cc: netdev, john.fastabend
In the devmap alloc map logic we check to ensure that the sizeof the
values are not greater than KMALLOC_MAX_SIZE. But, in the dev map case
we ensure the value size is 4bytes earlier in the function because all
values should be netdev ifindex values.
The second check is harmless but is not needed so remove it.
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
kernel/bpf/devmap.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index 7192fb6..18a72a8 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -83,12 +83,6 @@ static struct bpf_map *dev_map_alloc(union bpf_attr *attr)
attr->value_size != 4 || attr->map_flags)
return ERR_PTR(-EINVAL);
- /* if value_size is bigger, the user space won't be able to
- * access the elements.
- */
- if (attr->value_size > KMALLOC_MAX_SIZE)
- return ERR_PTR(-E2BIG);
-
dtab = kzalloc(sizeof(*dtab), GFP_USER);
if (!dtab)
return ERR_PTR(-ENOMEM);
^ permalink raw reply related
* [PATCH net V3] openvswitch: fix skb_panic due to the incorrect actions attrlen
From: Liping Zhang @ 2017-08-16 5:30 UTC (permalink / raw)
To: pshelar, davem; +Cc: netdev, Liping Zhang, Neil McKee
From: Liping Zhang <zlpnobody@gmail.com>
For sw_flow_actions, the actions_len only represents the kernel part's
size, and when we dump the actions to the userspace, we will do the
convertions, so it's true size may become bigger than the actions_len.
But unfortunately, for OVS_PACKET_ATTR_ACTIONS, we use the actions_len
to alloc the skbuff, so the user_skb's size may become insufficient and
oops will happen like this:
skbuff: skb_over_panic: text:ffffffff8148fabf len:1749 put:157 head:
ffff881300f39000 data:ffff881300f39000 tail:0x6d5 end:0x6c0 dev:<NULL>
------------[ cut here ]------------
kernel BUG at net/core/skbuff.c:129!
[...]
Call Trace:
<IRQ>
[<ffffffff8148be82>] skb_put+0x43/0x44
[<ffffffff8148fabf>] skb_zerocopy+0x6c/0x1f4
[<ffffffffa0290d36>] queue_userspace_packet+0x3a3/0x448 [openvswitch]
[<ffffffffa0292023>] ovs_dp_upcall+0x30/0x5c [openvswitch]
[<ffffffffa028d435>] output_userspace+0x132/0x158 [openvswitch]
[<ffffffffa01e6890>] ? ip6_rcv_finish+0x74/0x77 [ipv6]
[<ffffffffa028e277>] do_execute_actions+0xcc1/0xdc8 [openvswitch]
[<ffffffffa028e3f2>] ovs_execute_actions+0x74/0x106 [openvswitch]
[<ffffffffa0292130>] ovs_dp_process_packet+0xe1/0xfd [openvswitch]
[<ffffffffa0292b77>] ? key_extract+0x63c/0x8d5 [openvswitch]
[<ffffffffa029848b>] ovs_vport_receive+0xa1/0xc3 [openvswitch]
[...]
Also we can find that the actions_len is much little than the orig_len:
crash> struct sw_flow_actions 0xffff8812f539d000
struct sw_flow_actions {
rcu = {
next = 0xffff8812f5398800,
func = 0xffffe3b00035db32
},
orig_len = 1384,
actions_len = 592,
actions = 0xffff8812f539d01c
}
So as a quick fix, use the orig_len instead of the actions_len to alloc
the user_skb.
Last, this oops happened on our system running a relative old kernel, but
the same risk still exists on the mainline, since we use the wrong
actions_len from the beginning.
Fixes: ccea74457bbd ("openvswitch: include datapath actions with sampled-packet upcall to userspace")
Cc: Neil McKee <neil.mckee@inmon.com>
Signed-off-by: Liping Zhang <zlpnobody@gmail.com>
---
V3: remove the unnecessary dp_upcall_info->actions_attrlen, suggested
by Pravin Shelar.
V2: move actions_attrlen into ovs_skb_cb, which will make codes more
clean, suggested by Pravin Shelar.
net/openvswitch/actions.c | 1 +
net/openvswitch/datapath.c | 7 ++++---
net/openvswitch/datapath.h | 2 ++
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index e4610676299b..a54a556fcdb5 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -1337,6 +1337,7 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
goto out;
}
+ OVS_CB(skb)->acts_origlen = acts->orig_len;
err = do_execute_actions(dp, skb, key,
acts->actions, acts->actions_len);
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 45fe8c8a884d..6b44fe405282 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -381,7 +381,7 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
}
static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info,
- unsigned int hdrlen)
+ unsigned int hdrlen, int actions_attrlen)
{
size_t size = NLMSG_ALIGN(sizeof(struct ovs_header))
+ nla_total_size(hdrlen) /* OVS_PACKET_ATTR_PACKET */
@@ -398,7 +398,7 @@ static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info,
/* OVS_PACKET_ATTR_ACTIONS */
if (upcall_info->actions_len)
- size += nla_total_size(upcall_info->actions_len);
+ size += nla_total_size(actions_attrlen);
/* OVS_PACKET_ATTR_MRU */
if (upcall_info->mru)
@@ -465,7 +465,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
else
hlen = skb->len;
- len = upcall_msg_size(upcall_info, hlen - cutlen);
+ len = upcall_msg_size(upcall_info, hlen - cutlen,
+ OVS_CB(skb)->acts_origlen);
user_skb = genlmsg_new(len, GFP_ATOMIC);
if (!user_skb) {
err = -ENOMEM;
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
index 5d8dcd88815f..480600649d0b 100644
--- a/net/openvswitch/datapath.h
+++ b/net/openvswitch/datapath.h
@@ -99,11 +99,13 @@ struct datapath {
* when a packet is received by OVS.
* @mru: The maximum received fragement size; 0 if the packet is not
* fragmented.
+ * @acts_origlen: The netlink size of the flow actions applied to this skb.
* @cutlen: The number of bytes from the packet end to be removed.
*/
struct ovs_skb_cb {
struct vport *input_vport;
u16 mru;
+ u16 acts_origlen;
u32 cutlen;
};
#define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
--
2.13.4
^ permalink raw reply related
* [PATCH v3] openvswitch: enable NSH support
From: Yi Yang @ 2017-08-16 5:35 UTC (permalink / raw)
To: netdev; +Cc: Yi Yang
v2->v3
- Change OVS_KEY_ATTR_NSH to nested key to handle
length-fixed attributes and length-variable
attriubte more flexibly.
- Remove struct ovs_action_push_nsh completely
- Add code to handle nested attribute for SET_MASKED
- Change PUSH_NSH to use the nested OVS_KEY_ATTR_NSH
to transfer NSH header data.
- Fix comments and coding style issues by Jiri and Eric
v1->v2
- Change encap_nsh and decap_nsh to push_nsh and pop_nsh
- Dynamically allocate struct ovs_action_push_nsh for
length-variable metadata.
OVS master and 2.8 branch has merged NSH userspace
patch series, this patch is to enable NSH support
in kernel data path in order that OVS can support
NSH in 2.8 release in compat mode by porting this.
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
---
drivers/net/vxlan.c | 7 +
include/net/nsh.h | 150 +++++++++++++++++++
include/uapi/linux/openvswitch.h | 30 ++++
net/openvswitch/actions.c | 175 ++++++++++++++++++++++
net/openvswitch/flow.c | 39 +++++
net/openvswitch/flow.h | 11 ++
net/openvswitch/flow_netlink.c | 304 ++++++++++++++++++++++++++++++++++++++-
net/openvswitch/flow_netlink.h | 4 +
8 files changed, 719 insertions(+), 1 deletion(-)
create mode 100644 include/net/nsh.h
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index dbca067..843714c 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -27,6 +27,7 @@
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/vxlan.h>
+#include <net/nsh.h>
#if IS_ENABLED(CONFIG_IPV6)
#include <net/ip6_tunnel.h>
@@ -1267,6 +1268,9 @@ static bool vxlan_parse_gpe_hdr(struct vxlanhdr *unparsed,
case VXLAN_GPE_NP_IPV6:
*protocol = htons(ETH_P_IPV6);
break;
+ case VXLAN_GPE_NP_NSH:
+ *protocol = htons(ETH_P_NSH);
+ break;
case VXLAN_GPE_NP_ETHERNET:
*protocol = htons(ETH_P_TEB);
break;
@@ -1806,6 +1810,9 @@ static int vxlan_build_gpe_hdr(struct vxlanhdr *vxh, u32 vxflags,
case htons(ETH_P_IPV6):
gpe->next_protocol = VXLAN_GPE_NP_IPV6;
return 0;
+ case htons(ETH_P_NSH):
+ gpe->next_protocol = VXLAN_GPE_NP_NSH;
+ return 0;
case htons(ETH_P_TEB):
gpe->next_protocol = VXLAN_GPE_NP_ETHERNET;
return 0;
diff --git a/include/net/nsh.h b/include/net/nsh.h
new file mode 100644
index 0000000..54f44f6
--- /dev/null
+++ b/include/net/nsh.h
@@ -0,0 +1,150 @@
+#ifndef __NET_NSH_H
+#define __NET_NSH_H 1
+
+
+/*
+ * Network Service Header:
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |Ver|O|C|R|R|R|R|R|R| Length | MD Type | Next Proto |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Service Path ID | Service Index |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * ~ Mandatory/Optional Context Header ~
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * Ver = The version field is used to ensure backward compatibility
+ * going forward with future NSH updates. It MUST be set to 0x0
+ * by the sender, in this first revision of NSH.
+ *
+ * O = OAM. when set to 0x1 indicates that this packet is an operations
+ * and management (OAM) packet. The receiving SFF and SFs nodes
+ * MUST examine the payload and take appropriate action.
+ *
+ * C = context. Indicates that a critical metadata TLV is present.
+ *
+ * Length : total length, in 4-byte words, of NSH including the Base
+ * Header, the Service Path Header and the optional variable
+ * TLVs.
+ * MD Type: indicates the format of NSH beyond the mandatory Base Header
+ * and the Service Path Header.
+ *
+ * Next Protocol: indicates the protocol type of the original packet. A
+ * new IANA registry will be created for protocol type.
+ *
+ * Service Path Identifier (SPI): identifies a service path.
+ * Participating nodes MUST use this identifier for Service
+ * Function Path selection.
+ *
+ * Service Index (SI): provides location within the SFP.
+ *
+ * [0] https://tools.ietf.org/html/draft-ietf-sfc-nsh-13
+ */
+
+/**
+ * struct nsh_md1_ctx - Keeps track of NSH context data
+ * @nshc<1-4>: NSH Contexts.
+ */
+struct nsh_md1_ctx {
+ __be32 context[4];
+};
+
+struct nsh_md2_tlv {
+ __be16 md_class;
+ u8 type;
+ u8 length;
+ u8 md_value[];
+};
+
+struct nsh_hdr {
+ __be16 ver_flags_len;
+ u8 md_type;
+ u8 next_proto;
+ __be32 path_hdr;
+ union {
+ struct nsh_md1_ctx md1;
+ struct nsh_md2_tlv md2[0];
+ };
+};
+
+#define NSH_M_TYPE2_MAX_LEN 256
+
+struct push_nsh_para {
+ __be16 ver_flags_len;
+ u8 md_type;
+ u8 next_proto;
+ __be32 path_hdr;
+ u8 metadata[NSH_M_TYPE2_MAX_LEN-8];
+};
+
+/* Masking NSH header fields. */
+#define NSH_VER_MASK 0xc000
+#define NSH_VER_SHIFT 14
+#define NSH_FLAGS_MASK 0x3fc0
+#define NSH_FLAGS_SHIFT 6
+#define NSH_LEN_MASK 0x003f
+#define NSH_LEN_SHIFT 0
+
+#define NSH_SPI_MASK 0xffffff00
+#define NSH_SPI_SHIFT 8
+#define NSH_SI_MASK 0x000000ff
+#define NSH_SI_SHIFT 0
+
+#define NSH_DST_PORT 4790 /* UDP Port for NSH on VXLAN. */
+#define ETH_P_NSH 0x894F /* Ethertype for NSH. */
+
+/* NSH Base Header Next Protocol. */
+#define NSH_P_IPV4 0x01
+#define NSH_P_IPV6 0x02
+#define NSH_P_ETHERNET 0x03
+#define NSH_P_NSH 0x04
+#define NSH_P_MPLS 0x05
+
+/* MD Type Registry. */
+#define NSH_M_TYPE1 0x01
+#define NSH_M_TYPE2 0x02
+#define NSH_M_EXP1 0xFE
+#define NSH_M_EXP2 0xFF
+
+/* NSH Metadata Length. */
+#define NSH_M_TYPE1_MDLEN 16
+
+/* NSH Base Header Length */
+#define NSH_BASE_HDR_LEN 8
+
+/* NSH MD Type 1 header Length. */
+#define NSH_M_TYPE1_LEN 24
+
+static inline u16 nsh_hdr_len(const struct nsh_hdr *nsh)
+{
+ return ((ntohs(nsh->ver_flags_len) & NSH_LEN_MASK)
+ >> NSH_LEN_SHIFT) << 2;
+}
+
+static inline struct nsh_md1_ctx *nsh_md1_ctx(struct nsh_hdr *nsh)
+{
+ return &nsh->md1;
+}
+
+static inline struct nsh_md2_tlv *nsh_md2_ctx(struct nsh_hdr *nsh)
+{
+ return nsh->md2;
+}
+
+static inline u8 nsh_get_ver(const struct nsh_hdr *nsh)
+{
+ return (ntohs(nsh->ver_flags_len) & NSH_VER_MASK) >> NSH_VER_SHIFT;
+}
+
+static inline u8 nsh_get_len(const struct nsh_hdr *nsh)
+{
+ return (ntohs(nsh->ver_flags_len) & NSH_LEN_MASK) >> NSH_LEN_SHIFT;
+}
+
+static inline u8 nsh_get_flags(const struct nsh_hdr *nsh)
+{
+ return (ntohs(nsh->ver_flags_len) & NSH_FLAGS_MASK)
+ >> NSH_FLAGS_SHIFT;
+}
+
+#endif /* __NET_NSH_H */
diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h
index 156ee4c..596a043 100644
--- a/include/uapi/linux/openvswitch.h
+++ b/include/uapi/linux/openvswitch.h
@@ -333,6 +333,7 @@ enum ovs_key_attr {
OVS_KEY_ATTR_CT_LABELS, /* 16-octet connection tracking label */
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4, /* struct ovs_key_ct_tuple_ipv4 */
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6, /* struct ovs_key_ct_tuple_ipv6 */
+ OVS_KEY_ATTR_NSH, /* Nested set of ovs_nsh_key_* */
#ifdef __KERNEL__
OVS_KEY_ATTR_TUNNEL_INFO, /* struct ip_tunnel_info */
@@ -491,6 +492,29 @@ struct ovs_key_ct_tuple_ipv6 {
__u8 ipv6_proto;
};
+enum ovs_nsh_key_attr {
+ OVS_NSH_KEY_ATTR_BASE, /* struct ovs_nsh_key_base. */
+ OVS_NSH_KEY_ATTR_MD1, /* struct ovs_nsh_key_md1. */
+ OVS_NSH_KEY_ATTR_MD2, /* variable-length octets for MD type 2. */
+ __OVS_NSH_KEY_ATTR_MAX
+};
+
+#define OVS_NSH_KEY_ATTR_MAX (__OVS_NSH_KEY_ATTR_MAX - 1)
+
+struct ovs_nsh_key_base {
+ __u8 flags;
+ __u8 mdtype;
+ __u8 np;
+ __u8 pad;
+ __be32 path_hdr;
+};
+
+#define NSH_MD1_CONTEXT_SIZE 4
+
+struct ovs_nsh_key_md1 {
+ __be32 context[NSH_MD1_CONTEXT_SIZE];
+};
+
/**
* enum ovs_flow_attr - attributes for %OVS_FLOW_* commands.
* @OVS_FLOW_ATTR_KEY: Nested %OVS_KEY_ATTR_* attributes specifying the flow
@@ -769,6 +793,8 @@ struct ovs_action_push_eth {
struct ovs_key_ethernet addresses;
};
+#define OVS_PUSH_NSH_MAX_MD_LEN 248
+
/**
* enum ovs_action_attr - Action types.
*
@@ -806,6 +832,8 @@ struct ovs_action_push_eth {
* packet.
* @OVS_ACTION_ATTR_POP_ETH: Pop the outermost Ethernet header off the
* packet.
+ * @OVS_ACTION_ATTR_PUSH_NSH: push NSH header to the packet.
+ * @OVS_ACTION_ATTR_POP_NSH: pop the outermost NSH header off the packet.
*
* Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all
* fields within a header are modifiable, e.g. the IPv4 protocol and fragment
@@ -835,6 +863,8 @@ enum ovs_action_attr {
OVS_ACTION_ATTR_TRUNC, /* u32 struct ovs_action_trunc. */
OVS_ACTION_ATTR_PUSH_ETH, /* struct ovs_action_push_eth. */
OVS_ACTION_ATTR_POP_ETH, /* No argument. */
+ OVS_ACTION_ATTR_PUSH_NSH, /* Nested OVS_NSH_KEY_ATTR_*. */
+ OVS_ACTION_ATTR_POP_NSH, /* No argument. */
__OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted
* from userspace. */
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index e461067..38df378 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -43,6 +43,7 @@
#include "flow.h"
#include "conntrack.h"
#include "vport.h"
+#include "flow_netlink.h"
struct deferred_action {
struct sk_buff *skb;
@@ -380,6 +381,98 @@ static int push_eth(struct sk_buff *skb, struct sw_flow_key *key,
return 0;
}
+static int push_nsh(struct sk_buff *skb, struct sw_flow_key *key,
+ const struct push_nsh_para *pnp)
+{
+ struct nsh_hdr *nsh;
+ size_t length = ((ntohs(pnp->ver_flags_len) & NSH_LEN_MASK)
+ >> NSH_LEN_SHIFT) << 2;
+ u8 next_proto;
+
+ if (key->mac_proto == MAC_PROTO_ETHERNET) {
+ next_proto = NSH_P_ETHERNET;
+ } else {
+ switch (ntohs(skb->protocol)) {
+ case ETH_P_IP:
+ next_proto = NSH_P_IPV4;
+ break;
+ case ETH_P_IPV6:
+ next_proto = NSH_P_IPV6;
+ break;
+ case ETH_P_NSH:
+ next_proto = NSH_P_NSH;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+ }
+
+ /* Add the NSH header */
+ if (skb_cow_head(skb, length) < 0)
+ return -ENOMEM;
+
+ skb_push(skb, length);
+ nsh = (struct nsh_hdr *)(skb->data);
+ memcpy(nsh, pnp, length);
+ nsh->next_proto = next_proto;
+
+ if (!skb->inner_protocol)
+ skb_set_inner_protocol(skb, skb->protocol);
+
+ skb->protocol = htons(ETH_P_NSH);
+ key->eth.type = htons(ETH_P_NSH);
+ skb_reset_mac_header(skb);
+ skb_reset_mac_len(skb);
+
+ /* safe right before invalidate_flow_key */
+ key->mac_proto = MAC_PROTO_NONE;
+ invalidate_flow_key(key);
+ return 0;
+}
+
+static int pop_nsh(struct sk_buff *skb, struct sw_flow_key *key)
+{
+ struct nsh_hdr *nsh = (struct nsh_hdr *)(skb->data);
+ size_t length;
+ u16 inner_proto;
+
+ if (ovs_key_mac_proto(key) != MAC_PROTO_NONE ||
+ skb->protocol != htons(ETH_P_NSH)) {
+ return -EINVAL;
+ }
+
+ switch (nsh->next_proto) {
+ case NSH_P_ETHERNET:
+ inner_proto = htons(ETH_P_TEB);
+ break;
+ case NSH_P_IPV4:
+ inner_proto = htons(ETH_P_IP);
+ break;
+ case NSH_P_IPV6:
+ inner_proto = htons(ETH_P_IPV6);
+ break;
+ case NSH_P_NSH:
+ inner_proto = htons(ETH_P_NSH);
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ length = nsh_hdr_len(nsh);
+ skb_pull(skb, length);
+ skb_reset_mac_header(skb);
+ skb_reset_mac_len(skb);
+ skb->protocol = inner_proto;
+
+ /* safe right before invalidate_flow_key */
+ if (inner_proto == htons(ETH_P_TEB))
+ key->mac_proto = MAC_PROTO_ETHERNET;
+ else
+ key->mac_proto = MAC_PROTO_NONE;
+ invalidate_flow_key(key);
+ return 0;
+}
+
static void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh,
__be32 addr, __be32 new_addr)
{
@@ -602,6 +695,50 @@ static int set_ipv6(struct sk_buff *skb, struct sw_flow_key *flow_key,
return 0;
}
+static int set_nsh(struct sk_buff *skb, struct sw_flow_key *flow_key,
+ const struct ovs_key_nsh *key,
+ const struct ovs_key_nsh *mask)
+{
+ struct nsh_hdr *nsh;
+ int err;
+ u8 flags;
+ int i;
+
+ err = skb_ensure_writable(skb, skb_network_offset(skb) +
+ sizeof(struct nsh_hdr));
+ if (unlikely(err))
+ return err;
+
+ nsh = (struct nsh_hdr *)skb_network_header(skb);
+
+ flags = (ntohs(nsh->ver_flags_len) & NSH_FLAGS_MASK) >>
+ NSH_FLAGS_SHIFT;
+ flags = OVS_MASKED(flags, key->flags, mask->flags);
+ flow_key->nsh.flags = flags;
+ nsh->ver_flags_len = htons(flags << NSH_FLAGS_SHIFT) |
+ (nsh->ver_flags_len & ~htons(NSH_FLAGS_MASK));
+ nsh->path_hdr = OVS_MASKED(nsh->path_hdr, key->path_hdr,
+ mask->path_hdr);
+ flow_key->nsh.path_hdr = nsh->path_hdr;
+ switch (nsh->md_type) {
+ case NSH_M_TYPE1:
+ for (i = 0; i < 4; i++) {
+ nsh->md1.context[i] =
+ OVS_MASKED(nsh->md1.context[i], key->context[i],
+ mask->context[i]);
+ flow_key->nsh.context[i] = nsh->md1.context[i];
+ }
+ break;
+ case NSH_M_TYPE2:
+ for (i = 0; i < 4; i++)
+ flow_key->nsh.context[i] = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
/* Must follow skb_ensure_writable() since that can move the skb data. */
static void set_tp_port(struct sk_buff *skb, __be16 *port,
__be16 new_port, __sum16 *check)
@@ -1024,6 +1161,31 @@ static int execute_masked_set_action(struct sk_buff *skb,
get_mask(a, struct ovs_key_ethernet *));
break;
+ case OVS_KEY_ATTR_NSH: {
+ struct ovs_key_nsh nsh;
+ struct ovs_key_nsh nsh_mask;
+ size_t size = nla_len(a) / 2;
+ struct nlattr attr[1 + DIV_ROUND_UP(sizeof(struct ovs_key_ipv6)
+ , sizeof(struct nlattr))];
+ struct nlattr mask[1 + DIV_ROUND_UP(sizeof(struct ovs_key_ipv6)
+ , sizeof(struct nlattr))];
+
+ attr->nla_type = nla_type(a);
+ mask->nla_type = attr->nla_type;
+ attr->nla_len = NLA_HDRLEN + size;
+ mask->nla_len = attr->nla_len;
+ memcpy(attr + 1, (char *)(a + 1), size);
+ memcpy(mask + 1, (char *)(a + 1) + size, size);
+ err = nsh_key_from_nlattr(attr, &nsh);
+ if (err)
+ break;
+ err = nsh_key_from_nlattr(attr, &nsh_mask);
+ if (err)
+ break;
+ err = set_nsh(skb, flow_key, &nsh, &nsh_mask);
+ break;
+ }
+
case OVS_KEY_ATTR_IPV4:
err = set_ipv4(skb, flow_key, nla_data(a),
get_mask(a, struct ovs_key_ipv4 *));
@@ -1210,6 +1372,19 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
case OVS_ACTION_ATTR_POP_ETH:
err = pop_eth(skb, key);
break;
+
+ case OVS_ACTION_ATTR_PUSH_NSH: {
+ struct push_nsh_para pnp;
+ const struct push_nsh_para *pnpp = &pnp;
+
+ push_nsh_para_from_nlattr(nla_data(a), &pnp);
+ err = push_nsh(skb, key, pnpp);
+ break;
+ }
+
+ case OVS_ACTION_ATTR_POP_NSH:
+ err = pop_nsh(skb, key);
+ break;
}
if (unlikely(err)) {
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index 8c94cef..e2d6463 100644
--- a/net/openvswitch/flow.c
+++ b/net/openvswitch/flow.c
@@ -46,6 +46,7 @@
#include <net/ipv6.h>
#include <net/mpls.h>
#include <net/ndisc.h>
+#include <net/nsh.h>
#include "conntrack.h"
#include "datapath.h"
@@ -490,6 +491,40 @@ static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key,
return 0;
}
+static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key)
+{
+ struct nsh_hdr *nsh = (struct nsh_hdr *)skb_network_header(skb);
+ u8 version, length;
+ u32 path_hdr;
+ int i;
+
+ memset(&key->nsh, 0, sizeof(struct ovs_key_nsh));
+ version = nsh_get_ver(nsh);
+ length = nsh_get_len(nsh);
+
+ key->nsh.flags = nsh_get_flags(nsh);
+ key->nsh.mdtype = nsh->md_type;
+ key->nsh.np = nsh->next_proto;
+ path_hdr = ntohl(nsh->path_hdr);
+ key->nsh.path_hdr = nsh->path_hdr;
+ switch (key->nsh.mdtype) {
+ case NSH_M_TYPE1:
+ if ((length << 2) != NSH_M_TYPE1_LEN)
+ return -EINVAL;
+
+ for (i = 0; i < 4; i++)
+ key->nsh.context[i] = nsh->md1.context[i];
+
+ break;
+ case NSH_M_TYPE2:
+ /* Don't support MD type 2 yet */
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/**
* key_extract - extracts a flow key from an Ethernet frame.
* @skb: sk_buff that contains the frame, with skb->data pointing to the
@@ -735,6 +770,10 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
memset(&key->tp, 0, sizeof(key->tp));
}
}
+ } else if (key->eth.type == htons(ETH_P_NSH)) {
+ error = parse_nsh(skb, key);
+ if (error)
+ return error;
}
return 0;
}
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h
index 1875bba..6c738d0 100644
--- a/net/openvswitch/flow.h
+++ b/net/openvswitch/flow.h
@@ -35,6 +35,7 @@
#include <net/inet_ecn.h>
#include <net/ip_tunnels.h>
#include <net/dst_metadata.h>
+#include <net/nsh.h>
struct sk_buff;
@@ -66,6 +67,15 @@ struct vlan_head {
(offsetof(struct sw_flow_key, recirc_id) + \
FIELD_SIZEOF(struct sw_flow_key, recirc_id))
+struct ovs_key_nsh {
+ __u8 flags;
+ __u8 mdtype;
+ __u8 np;
+ __u8 pad;
+ __be32 path_hdr;
+ __be32 context[NSH_MD1_CONTEXT_SIZE];
+};
+
struct sw_flow_key {
u8 tun_opts[IP_TUNNEL_OPTS_MAX];
u8 tun_opts_len;
@@ -144,6 +154,7 @@ struct sw_flow_key {
};
} ipv6;
};
+ struct ovs_key_nsh nsh; /* network service header */
struct {
/* Connection tracking fields not packed above. */
struct {
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index f07d10a..79059db 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -78,9 +78,11 @@ static bool actions_may_change_flow(const struct nlattr *actions)
case OVS_ACTION_ATTR_HASH:
case OVS_ACTION_ATTR_POP_ETH:
case OVS_ACTION_ATTR_POP_MPLS:
+ case OVS_ACTION_ATTR_POP_NSH:
case OVS_ACTION_ATTR_POP_VLAN:
case OVS_ACTION_ATTR_PUSH_ETH:
case OVS_ACTION_ATTR_PUSH_MPLS:
+ case OVS_ACTION_ATTR_PUSH_NSH:
case OVS_ACTION_ATTR_PUSH_VLAN:
case OVS_ACTION_ATTR_SAMPLE:
case OVS_ACTION_ATTR_SET:
@@ -322,12 +324,22 @@ size_t ovs_tun_key_attr_size(void)
+ nla_total_size(2); /* OVS_TUNNEL_KEY_ATTR_TP_DST */
}
+size_t ovs_nsh_key_attr_size(void)
+{
+ /* Whenever adding new OVS_NSH_KEY_ FIELDS, we should consider
+ * updating this function.
+ */
+ return nla_total_size(8) /* OVS_NSH_KEY_ATTR_BASE */
+ + nla_total_size(16) /* OVS_NSH_KEY_ATTR_MD1 */
+ + nla_total_size(248); /* OVS_NSH_KEY_ATTR_MD2 */
+}
+
size_t ovs_key_attr_size(void)
{
/* Whenever adding new OVS_KEY_ FIELDS, we should consider
* updating this function.
*/
- BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 28);
+ BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 29);
return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
+ nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
@@ -341,6 +353,8 @@ size_t ovs_key_attr_size(void)
+ nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */
+ nla_total_size(16) /* OVS_KEY_ATTR_CT_LABELS */
+ nla_total_size(40) /* OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6 */
+ + nla_total_size(0) /* OVS_KEY_ATTR_NSH */
+ + ovs_nsh_key_attr_size()
+ nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */
+ nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
+ nla_total_size(4) /* OVS_KEY_ATTR_VLAN */
@@ -373,6 +387,13 @@ static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1]
[OVS_TUNNEL_KEY_ATTR_IPV6_DST] = { .len = sizeof(struct in6_addr) },
};
+static const struct ovs_len_tbl
+ovs_nsh_key_attr_lens[OVS_NSH_KEY_ATTR_MAX + 1] = {
+ [OVS_NSH_KEY_ATTR_BASE] = { .len = 8 },
+ [OVS_NSH_KEY_ATTR_MD1] = { .len = 16 },
+ [OVS_NSH_KEY_ATTR_MD2] = { .len = OVS_ATTR_VARIABLE },
+};
+
/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */
static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
[OVS_KEY_ATTR_ENCAP] = { .len = OVS_ATTR_NESTED },
@@ -405,6 +426,8 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
.len = sizeof(struct ovs_key_ct_tuple_ipv4) },
[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6] = {
.len = sizeof(struct ovs_key_ct_tuple_ipv6) },
+ [OVS_KEY_ATTR_NSH] = { .len = OVS_ATTR_NESTED,
+ .next = ovs_nsh_key_attr_lens, },
};
static bool check_attr_len(unsigned int attr_len, unsigned int expected_len)
@@ -1179,6 +1202,209 @@ static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
return 0;
}
+int push_nsh_para_from_nlattr(const struct nlattr *attr,
+ struct push_nsh_para *pnp)
+{
+ struct nlattr *a;
+ int rem;
+ u8 flags = 0;
+ size_t mdlen = 0;
+
+ nla_for_each_nested(a, attr, rem) {
+ int type = nla_type(a);
+
+ if (type > OVS_NSH_KEY_ATTR_MAX) {
+ OVS_NLERR(1, "nsh attr %d is out of range max %d",
+ type, OVS_NSH_KEY_ATTR_MAX);
+ return -EINVAL;
+ }
+
+ if (!check_attr_len(nla_len(a),
+ ovs_nsh_key_attr_lens[type].len)) {
+ OVS_NLERR(
+ 1,
+ "nsh attr %d has unexpected len %d expected %d",
+ type,
+ nla_len(a),
+ ovs_nsh_key_attr_lens[type].len
+ );
+ return -EINVAL;
+ }
+
+ switch (type) {
+ case OVS_NSH_KEY_ATTR_BASE: {
+ const struct ovs_nsh_key_base *base =
+ (struct ovs_nsh_key_base *)nla_data(a);
+ flags = base->flags;
+ pnp->next_proto = base->np;
+ pnp->md_type = base->mdtype;
+ pnp->path_hdr = base->path_hdr;
+ break;
+ }
+ case OVS_NSH_KEY_ATTR_MD1: {
+ const struct ovs_nsh_key_md1 *md1 =
+ (struct ovs_nsh_key_md1 *)nla_data(a);
+
+ mdlen = nla_len(a);
+ memcpy(pnp->metadata, md1, mdlen);
+ break;
+ }
+ case OVS_NSH_KEY_ATTR_MD2: {
+ const struct u8 *md2 = nla_data(a);
+
+ mdlen = nla_len(a);
+ memcpy(pnp->metadata, md2, mdlen);
+ break;
+ }
+ default:
+ OVS_NLERR(1, "Unknown nsh attribute %d",
+ type);
+ return -EINVAL;
+ }
+ }
+
+ if (rem > 0) {
+ OVS_NLERR(1, "nsh attribute has %d unknown bytes.", rem);
+ return -EINVAL;
+ }
+
+ /* nsh header length = NSH_BASE_HDR_LEN + mdlen */
+ pnp->ver_flags_len = htons(flags << NSH_FLAGS_SHIFT |
+ (NSH_BASE_HDR_LEN + mdlen) >> 2);
+
+ return 0;
+}
+
+int nsh_key_from_nlattr(const struct nlattr *attr,
+ struct ovs_key_nsh *nsh)
+{
+ struct nlattr *a;
+ int rem;
+
+ nla_for_each_nested(a, attr, rem) {
+ int type = nla_type(a);
+
+ if (type > OVS_NSH_KEY_ATTR_MAX) {
+ OVS_NLERR(1, "nsh attr %d is out of range max %d",
+ type, OVS_NSH_KEY_ATTR_MAX);
+ return -EINVAL;
+ }
+
+ if (!check_attr_len(nla_len(a),
+ ovs_nsh_key_attr_lens[type].len)) {
+ OVS_NLERR(
+ 1,
+ "nsh attr %d has unexpected len %d expected %d",
+ type,
+ nla_len(a),
+ ovs_nsh_key_attr_lens[type].len
+ );
+ return -EINVAL;
+ }
+
+ switch (type) {
+ case OVS_NSH_KEY_ATTR_BASE: {
+ const struct ovs_nsh_key_base *base =
+ (struct ovs_nsh_key_base *)nla_data(a);
+ nsh->flags = base->flags;
+ nsh->mdtype = base->mdtype;
+ nsh->np = base->np;
+ nsh->path_hdr = base->path_hdr;
+ break;
+ }
+ case OVS_NSH_KEY_ATTR_MD1: {
+ const struct ovs_nsh_key_md1 *md1 =
+ (struct ovs_nsh_key_md1 *)nla_data(a);
+ memcpy(nsh->context, md1->context, sizeof(*md1));
+ break;
+ }
+ case OVS_NSH_KEY_ATTR_MD2:
+ /* Not supported yet */
+ break;
+ default:
+ OVS_NLERR(1, "Unknown nsh attribute %d",
+ type);
+ return -EINVAL;
+ }
+ }
+
+ if (rem > 0) {
+ OVS_NLERR(1, "nsh attribute has %d unknown bytes.", rem);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int nsh_key_put_from_nlattr(const struct nlattr *attr,
+ struct sw_flow_match *match, bool is_mask,
+ bool log)
+{
+ struct nlattr *a;
+ int rem;
+
+ nla_for_each_nested(a, attr, rem) {
+ int type = nla_type(a);
+ int i;
+
+ if (type > OVS_NSH_KEY_ATTR_MAX) {
+ OVS_NLERR(log, "nsh attr %d is out of range max %d",
+ type, OVS_NSH_KEY_ATTR_MAX);
+ return -EINVAL;
+ }
+
+ if (!check_attr_len(nla_len(a),
+ ovs_nsh_key_attr_lens[type].len)) {
+ OVS_NLERR(
+ log,
+ "nsh attr %d has unexpected len %d expected %d",
+ type,
+ nla_len(a),
+ ovs_nsh_key_attr_lens[type].len
+ );
+ return -EINVAL;
+ }
+
+ switch (type) {
+ case OVS_NSH_KEY_ATTR_BASE: {
+ const struct ovs_nsh_key_base *base =
+ (struct ovs_nsh_key_base *)nla_data(a);
+ SW_FLOW_KEY_PUT(match, nsh.flags,
+ base->flags, is_mask);
+ SW_FLOW_KEY_PUT(match, nsh.mdtype,
+ base->mdtype, is_mask);
+ SW_FLOW_KEY_PUT(match, nsh.np,
+ base->np, is_mask);
+ SW_FLOW_KEY_PUT(match, nsh.path_hdr,
+ base->path_hdr, is_mask);
+ break;
+ }
+ case OVS_NSH_KEY_ATTR_MD1: {
+ const struct ovs_nsh_key_md1 *md1 =
+ (struct ovs_nsh_key_md1 *)nla_data(a);
+ for (i = 0; i < 4; i++)
+ SW_FLOW_KEY_PUT(match, nsh.context[i],
+ md1->context[i], is_mask);
+ break;
+ }
+ case OVS_NSH_KEY_ATTR_MD2:
+ /* Not supported yet */
+ break;
+ default:
+ OVS_NLERR(log, "Unknown nsh attribute %d",
+ type);
+ return -EINVAL;
+ }
+ }
+
+ if (rem > 0) {
+ OVS_NLERR(log, "nsh attribute has %d unknown bytes.", rem);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match,
u64 attrs, const struct nlattr **a,
bool is_mask, bool log)
@@ -1306,6 +1532,13 @@ static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match,
attrs &= ~(1 << OVS_KEY_ATTR_ARP);
}
+ if (attrs & (1 << OVS_KEY_ATTR_NSH)) {
+ if (nsh_key_put_from_nlattr(a[OVS_KEY_ATTR_NSH], match,
+ is_mask, log) < 0)
+ return -EINVAL;
+ attrs &= ~(1 << OVS_KEY_ATTR_NSH);
+ }
+
if (attrs & (1 << OVS_KEY_ATTR_MPLS)) {
const struct ovs_key_mpls *mpls_key;
@@ -1622,6 +1855,43 @@ static int ovs_nla_put_vlan(struct sk_buff *skb, const struct vlan_head *vh,
return 0;
}
+static int nsh_key_to_nlattr(const struct ovs_key_nsh *nsh, bool is_mask,
+ struct sk_buff *skb)
+{
+ struct nlattr *start;
+ struct ovs_nsh_key_base base;
+ struct ovs_nsh_key_md1 md1;
+
+ base.flags = nsh->flags;
+ base.mdtype = nsh->mdtype;
+ base.np = nsh->np;
+ base.path_hdr = nsh->path_hdr;
+
+ if (is_mask || nsh->mdtype == NSH_M_TYPE1)
+ memcpy(md1.context, nsh->context, sizeof(md1));
+
+ start = nla_nest_start(skb, OVS_KEY_ATTR_NSH);
+ if (!start)
+ return -EMSGSIZE;
+
+ if (nla_put(skb, OVS_NSH_KEY_ATTR_BASE, sizeof(base), &base))
+ goto nla_put_failure;
+
+ if (is_mask || nsh->mdtype == NSH_M_TYPE1) {
+ if (nla_put(skb, OVS_NSH_KEY_ATTR_MD1, sizeof(md1), &md1))
+ goto nla_put_failure;
+ }
+
+ /* Don't support MD type 2 yet */
+
+ nla_nest_end(skb, start);
+
+ return 0;
+
+nla_put_failure:
+ return -EMSGSIZE;
+}
+
static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
const struct sw_flow_key *output, bool is_mask,
struct sk_buff *skb)
@@ -1750,6 +2020,9 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
ipv6_key->ipv6_tclass = output->ip.tos;
ipv6_key->ipv6_hlimit = output->ip.ttl;
ipv6_key->ipv6_frag = output->ip.frag;
+ } else if (swkey->eth.type == htons(ETH_P_NSH)) {
+ if (nsh_key_to_nlattr(&output->nsh, is_mask, skb))
+ goto nla_put_failure;
} else if (swkey->eth.type == htons(ETH_P_ARP) ||
swkey->eth.type == htons(ETH_P_RARP)) {
struct ovs_key_arp *arp_key;
@@ -2242,6 +2515,17 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
return err;
}
+static bool validate_nsh(const struct nlattr *attr, bool is_mask, bool log)
+{
+ struct sw_flow_match match;
+ struct sw_flow_key key;
+ int ret = 0;
+
+ ovs_match_init(&match, &key, true, NULL);
+ ret = nsh_key_put_from_nlattr(nla_data(attr), &match, is_mask, log);
+ return ((ret != 0) ? false : true);
+}
+
/* Return false if there are any non-masked bits set.
* Mask follows data immediately, before any netlink padding.
*/
@@ -2384,6 +2668,11 @@ static int validate_set(const struct nlattr *a,
break;
+ case OVS_KEY_ATTR_NSH:
+ if (!validate_nsh(a, masked, log))
+ return -EINVAL;
+ break;
+
default:
return -EINVAL;
}
@@ -2482,6 +2771,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
[OVS_ACTION_ATTR_TRUNC] = sizeof(struct ovs_action_trunc),
[OVS_ACTION_ATTR_PUSH_ETH] = sizeof(struct ovs_action_push_eth),
[OVS_ACTION_ATTR_POP_ETH] = 0,
+ [OVS_ACTION_ATTR_PUSH_NSH] = (u32)-1,
+ [OVS_ACTION_ATTR_POP_NSH] = 0,
};
const struct ovs_action_push_vlan *vlan;
int type = nla_type(a);
@@ -2636,6 +2927,17 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
mac_proto = MAC_PROTO_ETHERNET;
break;
+ case OVS_ACTION_ATTR_PUSH_NSH:
+ mac_proto = MAC_PROTO_NONE;
+ break;
+
+ case OVS_ACTION_ATTR_POP_NSH:
+ if (key->nsh.np == NSH_P_ETHERNET)
+ mac_proto = MAC_PROTO_ETHERNET;
+ else
+ mac_proto = MAC_PROTO_NONE;
+ break;
+
default:
OVS_NLERR(log, "Unknown Action type %d", type);
return -EINVAL;
diff --git a/net/openvswitch/flow_netlink.h b/net/openvswitch/flow_netlink.h
index 929c665..f9c14be 100644
--- a/net/openvswitch/flow_netlink.h
+++ b/net/openvswitch/flow_netlink.h
@@ -79,4 +79,8 @@ int ovs_nla_put_actions(const struct nlattr *attr,
void ovs_nla_free_flow_actions(struct sw_flow_actions *);
void ovs_nla_free_flow_actions_rcu(struct sw_flow_actions *);
+int nsh_key_from_nlattr(const struct nlattr *attr, struct ovs_key_nsh *nsh);
+int push_nsh_para_from_nlattr(const struct nlattr *attr,
+ struct push_nsh_para *pnp);
+
#endif /* flow_netlink.h */
--
2.5.5
^ permalink raw reply related
* Re: [PATCH net repost] nfp: do not update MTU from BH in flower app
From: Simon Horman @ 2017-08-16 5:35 UTC (permalink / raw)
To: David Miller; +Cc: jakub.kicinski, netdev, oss-drivers
In-Reply-To: <20170815.210358.1704629747295212922.davem@davemloft.net>
On Tue, Aug 15, 2017 at 09:03:58PM -0700, David Miller wrote:
> From: David Miller <davem@davemloft.net>
> Date: Tue, 15 Aug 2017 17:52:40 -0700 (PDT)
>
> > From: Simon Horman <simon.horman@netronome.com>
> > Date: Tue, 15 Aug 2017 08:13:48 +0200
> >
> >> Could you pull net into net-next? I'd like to send up a follow-up
> >> for net-next to allow processing of the MTU.
> >
> > Once Linus takes the pull request I just sent to him, I will
> > do this.
>
> And this is now done.
Great, thanks.
^ permalink raw reply
* [net-next PATCH 10/10] bpf: selftests add sockmap tests
From: John Fastabend @ 2017-08-16 5:34 UTC (permalink / raw)
To: davem, daniel, ast; +Cc: tgraf, netdev, john.fastabend, tom
In-Reply-To: <20170816052338.15445.83732.stgit@john-Precision-Tower-5810>
This generates a set of sockets, attaches BPF programs, and sends some
simple traffic using basic send/recv pattern. Additionally, we do a bunch
of negative tests to ensure adding/removing socks out of the sockmap fail
correctly.
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
tools/lib/bpf/libbpf.c | 29 ++
tools/lib/bpf/libbpf.h | 2
tools/testing/selftests/bpf/Makefile | 2
tools/testing/selftests/bpf/sockmap_parse_prog.c | 38 ++
tools/testing/selftests/bpf/sockmap_verdict_prog.c | 48 +++
tools/testing/selftests/bpf/test_maps.c | 308 ++++++++++++++++++++
tools/testing/selftests/bpf/test_progs.c | 55 +---
7 files changed, 443 insertions(+), 39 deletions(-)
create mode 100644 tools/testing/selftests/bpf/sockmap_parse_prog.c
create mode 100644 tools/testing/selftests/bpf/sockmap_verdict_prog.c
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 1a2c07e..1cc3ea0 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -1744,3 +1744,32 @@ long libbpf_get_error(const void *ptr)
return PTR_ERR(ptr);
return 0;
}
+
+int bpf_prog_load(const char *file, enum bpf_prog_type type,
+ struct bpf_object **pobj, int *prog_fd)
+{
+ struct bpf_program *prog;
+ struct bpf_object *obj;
+ int err;
+
+ obj = bpf_object__open(file);
+ if (IS_ERR(obj))
+ return -ENOENT;
+
+ prog = bpf_program__next(NULL, obj);
+ if (!prog) {
+ bpf_object__close(obj);
+ return -ENOENT;
+ }
+
+ bpf_program__set_type(prog, type);
+ err = bpf_object__load(obj);
+ if (err) {
+ bpf_object__close(obj);
+ return -EINVAL;
+ }
+
+ *pobj = obj;
+ *prog_fd = bpf_program__fd(prog);
+ return 0;
+}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 32c7252..7959086 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -243,4 +243,6 @@ int bpf_map__set_priv(struct bpf_map *map, void *priv,
long libbpf_get_error(const void *ptr);
+int bpf_prog_load(const char *file, enum bpf_prog_type type,
+ struct bpf_object **pobj, int *prog_fd);
#endif
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 3c2e67d..f4b23d6 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -15,7 +15,7 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test
test_align
TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \
- test_pkt_md_access.o test_xdp_redirect.o
+ test_pkt_md_access.o test_xdp_redirect.o sockmap_parse_prog.o sockmap_verdict_prog.o
TEST_PROGS := test_kmod.sh test_xdp_redirect.sh
diff --git a/tools/testing/selftests/bpf/sockmap_parse_prog.c b/tools/testing/selftests/bpf/sockmap_parse_prog.c
new file mode 100644
index 0000000..8b54531
--- /dev/null
+++ b/tools/testing/selftests/bpf/sockmap_parse_prog.c
@@ -0,0 +1,38 @@
+#include <linux/bpf.h>
+#include "bpf_helpers.h"
+#include "bpf_util.h"
+#include "bpf_endian.h"
+
+int _version SEC("version") = 1;
+
+#define bpf_printk(fmt, ...) \
+({ \
+ char ____fmt[] = fmt; \
+ bpf_trace_printk(____fmt, sizeof(____fmt), \
+ ##__VA_ARGS__); \
+})
+
+SEC("sk_skb1")
+int bpf_prog1(struct __sk_buff *skb)
+{
+ void *data_end = (void *)(long) skb->data_end;
+ void *data = (void *)(long) skb->data;
+ __u32 lport = skb->local_port;
+ __u32 rport = skb->remote_port;
+ char *d = data;
+
+ if (data + 8 > data_end)
+ return skb->len;
+
+ /* This write/read is a bit pointless but tests the verifier and
+ * strparser handler for read/write pkt data and access into sk
+ * fields.
+ */
+ d[0] = 1;
+
+ bpf_printk("data[0] = (%u): local_port %i remote %i\n",
+ d[0], lport, bpf_ntohl(rport));
+ return skb->len;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/sockmap_verdict_prog.c b/tools/testing/selftests/bpf/sockmap_verdict_prog.c
new file mode 100644
index 0000000..d5f9447
--- /dev/null
+++ b/tools/testing/selftests/bpf/sockmap_verdict_prog.c
@@ -0,0 +1,48 @@
+#include <linux/bpf.h>
+#include "bpf_helpers.h"
+#include "bpf_util.h"
+#include "bpf_endian.h"
+
+int _version SEC("version") = 1;
+
+#define bpf_printk(fmt, ...) \
+({ \
+ char ____fmt[] = fmt; \
+ bpf_trace_printk(____fmt, sizeof(____fmt), \
+ ##__VA_ARGS__); \
+})
+
+struct bpf_map_def SEC("maps") sock_map = {
+ .type = BPF_MAP_TYPE_SOCKMAP,
+ .key_size = sizeof(int),
+ .value_size = sizeof(int),
+ .max_entries = 20,
+};
+
+SEC("sk_skb2")
+int bpf_prog2(struct __sk_buff *skb)
+{
+ void *data_end = (void *)(long) skb->data_end;
+ void *data = (void *)(long) skb->data;
+ __u32 lport = skb->local_port;
+ __u32 rport = skb->remote_port;
+ char *d = data;
+
+ if (data + 8 > data_end)
+ return SK_DROP;
+
+ d[0] = 0xd;
+ d[1] = 0xe;
+ d[2] = 0xa;
+ d[3] = 0xd;
+ d[4] = 0xb;
+ d[5] = 0xe;
+ d[6] = 0xe;
+ d[7] = 0xf;
+
+ bpf_printk("data[0] = (%u): local_port %i remote %i\n",
+ d[0], lport, bpf_ntohl(rport));
+ return bpf_sk_redirect_map(&sock_map, 5, 0);
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c
index c991ab6..40b2d1f 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -22,6 +22,7 @@
#include <linux/bpf.h>
#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
#include "bpf_util.h"
static int map_flags;
@@ -453,6 +454,312 @@ static void test_devmap(int task, void *data)
close(fd);
}
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <sys/select.h>
+#include <linux/err.h>
+#define SOCKMAP_PARSE_PROG "./sockmap_parse_prog.o"
+#define SOCKMAP_VERDICT_PROG "./sockmap_verdict_prog.o"
+static void test_sockmap(int task, void *data)
+{
+ int ports[] = {50200, 50201, 50202, 50204};
+ int err, i, fd, sfd[6] = {0xdeadbeef};
+ char buf[] = "hello sockmap user\n";
+ int one = 1, map_fd, s, sc, rc;
+ int parse_prog, verdict_prog;
+ struct bpf_map *bpf_map;
+ struct sockaddr_in addr;
+ struct bpf_object *obj;
+ struct timeval to;
+ __u32 key, value;
+ fd_set w;
+
+ /* Create some sockets to use with sockmap */
+ for (i = 0; i < 2; i++) {
+ sfd[i] = socket(AF_INET, SOCK_STREAM, 0);
+ if (sfd[i] < 0)
+ goto out;
+ err = setsockopt(sfd[i], SOL_SOCKET, SO_REUSEADDR,
+ (char *)&one, sizeof(one));
+ if (err) {
+ printf("failed to setsockopt\n");
+ goto out;
+ }
+ err = ioctl(sfd[i], FIONBIO, (char *)&one);
+ if (err < 0) {
+ printf("failed to ioctl\n");
+ goto out;
+ }
+ memset(&addr, 0, sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ addr.sin_port = htons(ports[i]);
+ err = bind(sfd[i], (struct sockaddr *)&addr, sizeof(addr));
+ if (err < 0) {
+ printf("failed to bind: err %i: %i:%i\n",
+ err, i, sfd[i]);
+ goto out;
+ }
+ err = listen(sfd[i], 32);
+ if (err < 0) {
+ printf("failed to listeen\n");
+ goto out;
+ }
+ }
+
+ for (i = 2; i < 4; i++) {
+ sfd[i] = socket(AF_INET, SOCK_STREAM, 0);
+ if (sfd[i] < 0)
+ goto out;
+ err = setsockopt(sfd[i], SOL_SOCKET, SO_REUSEADDR,
+ (char *)&one, sizeof(one));
+ if (err) {
+ printf("set sock opt\n");
+ goto out;
+ }
+ memset(&addr, 0, sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ addr.sin_port = htons(ports[i - 2]);
+ err = connect(sfd[i], (struct sockaddr *)&addr, sizeof(addr));
+ if (err) {
+ printf("failed to conenct\n");
+ goto out;
+ }
+ }
+
+
+ for (i = 4; i < 6; i++) {
+ sfd[i] = accept(sfd[i - 4], NULL, NULL);
+ if (sfd[i] < 0) {
+ printf("accept failed\n");
+ goto out;
+ }
+ }
+
+ /* Test sockmap with connected sockets */
+ fd = bpf_create_map(BPF_MAP_TYPE_SOCKMAP,
+ sizeof(key), sizeof(value),
+ 6, 0);
+ if (fd < 0) {
+ printf("Failed to create sockmap %i\n", fd);
+ goto out_sockmap;
+ }
+
+ /* Nothing attached so these should fail */
+ for (i = 0; i < 6; i++) {
+ err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY);
+ if (!err) {
+ printf("Failed invalid update sockmap '%i:%i'\n",
+ i, sfd[i]);
+ goto out_sockmap;
+ }
+ }
+
+ /* Test attaching bad fds */
+ err = __bpf_prog_attach(-1, -2, fd, BPF_CGROUP_SMAP_INGRESS, 0);
+ if (!err) {
+ printf("Failed invalid prog attach\n");
+ goto out_sockmap;
+ }
+
+ /* Load SK_SKB program and Attach */
+ err = bpf_prog_load(SOCKMAP_PARSE_PROG,
+ BPF_PROG_TYPE_SK_SKB, &obj, &parse_prog);
+ if (err) {
+ printf("Failed to load SK_SKB parse prog\n");
+ goto out_sockmap;
+ }
+
+ err = bpf_prog_load(SOCKMAP_VERDICT_PROG,
+ BPF_PROG_TYPE_SK_SKB, &obj, &verdict_prog);
+ if (err) {
+ printf("Failed to load SK_SKB verdict prog\n");
+ goto out_sockmap;
+ }
+
+ bpf_map = bpf_object__find_map_by_name(obj, "sock_map");
+ if (IS_ERR(bpf_map)) {
+ printf("Failed to load map from verdict prog\n");
+ goto out_sockmap;
+ }
+
+ map_fd = bpf_map__fd(bpf_map);
+ if (map_fd < 0) {
+ printf("Failed to get map fd\n");
+ goto out_sockmap;
+ }
+
+ err = __bpf_prog_attach(parse_prog, verdict_prog, map_fd,
+ BPF_CGROUP_SMAP_INGRESS, 0);
+ if (err) {
+ printf("Failed bpf prog attach\n");
+ goto out_sockmap;
+ }
+
+ /* Test map update elem */
+ for (i = 0; i < 6; i++) {
+ err = bpf_map_update_elem(map_fd, &i, &sfd[i], BPF_ANY);
+ if (err) {
+ printf("Failed map_fd update sockmap %i '%i:%i'\n",
+ err, i, sfd[i]);
+ goto out_sockmap;
+ }
+ }
+
+ /* Test map delete elem and remove send/recv sockets */
+ for (i = 2; i < 4; i++) {
+ err = bpf_map_delete_elem(map_fd, &i);
+ if (err) {
+ printf("Failed delete sockmap %i '%i:%i'\n",
+ err, i, sfd[i]);
+ goto out_sockmap;
+ }
+ }
+
+ /* Test map send/recv */
+ sc = send(sfd[2], buf, 10, 0);
+ if (sc < 0) {
+ printf("Failed sockmap send\n");
+ goto out_sockmap;
+ }
+
+ FD_ZERO(&w);
+ FD_SET(sfd[3], &w);
+ to.tv_sec = 1;
+ to.tv_usec = 0;
+ s = select(sfd[3] + 1, &w, NULL, NULL, &to);
+ if (s == -1) {
+ perror("Failed sockmap select()");
+ goto out_sockmap;
+ } else if (!s) {
+ printf("Failed sockmap unexpected timeout\n");
+ goto out_sockmap;
+ }
+
+ if (!FD_ISSET(sfd[3], &w)) {
+ printf("Failed sockmap select/recv\n");
+ goto out_sockmap;
+ }
+
+ rc = recv(sfd[3], buf, sizeof(buf), 0);
+ if (rc < 0) {
+ printf("Failed sockmap recv\n");
+ goto out_sockmap;
+ }
+
+ /* Delete the reset of the elems include some NULL elems */
+ for (i = 0; i < 6; i++) {
+ err = bpf_map_delete_elem(map_fd, &i);
+ if (err && (i == 0 || i == 1 || i >= 4)) {
+ printf("Failed delete sockmap %i '%i:%i'\n",
+ err, i, sfd[i]);
+ goto out_sockmap;
+ } else if (!err && (i == 2 || i == 3)) {
+ printf("Failed null delete sockmap %i '%i:%i'\n",
+ err, i, sfd[i]);
+ goto out_sockmap;
+ }
+ }
+
+ /* Test having multiple SMAPs open and active on same fds */
+ err = __bpf_prog_attach(parse_prog, verdict_prog, fd,
+ BPF_CGROUP_SMAP_INGRESS, 0);
+ if (err) {
+ printf("Failed fd bpf prog attach\n");
+ goto out_sockmap;
+ }
+
+ for (i = 0; i < 6; i++) {
+ err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY);
+ if (err) {
+ printf("Failed fd update sockmap %i '%i:%i'\n",
+ err, i, sfd[i]);
+ goto out_sockmap;
+ }
+ }
+
+ /* Test duplicate socket add of NOEXIST, ANY and EXIST */
+ i = 0;
+ err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_NOEXIST);
+ if (!err) {
+ printf("Failed BPF_NOEXIST create\n");
+ goto out_sockmap;
+ }
+
+ err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY);
+ if (err) {
+ printf("Failed sockmap update BPF_ANY\n");
+ goto out_sockmap;
+ }
+
+ err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_EXIST);
+ if (err) {
+ printf("Failed sockmap update BPF_EXIST\n");
+ goto out_sockmap;
+ }
+
+ /* The above were pushing fd into same slot try different slot now */
+ i = 2;
+ err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_NOEXIST);
+ if (!err) {
+ printf("Failed BPF_NOEXIST create\n");
+ goto out_sockmap;
+ }
+
+ err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY);
+ if (err) {
+ printf("Failed sockmap update BPF_ANY\n");
+ goto out_sockmap;
+ }
+
+ err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_EXIST);
+ if (err) {
+ printf("Failed sockmap update BPF_EXIST\n");
+ goto out_sockmap;
+ }
+
+ /* Try pushing fd into different map, this is not allowed at the
+ * moment. Which programs would we use?
+ */
+ err = bpf_map_update_elem(map_fd, &i, &sfd[i], BPF_NOEXIST);
+ if (!err) {
+ printf("Failed BPF_NOEXIST create\n");
+ goto out_sockmap;
+ }
+
+ err = bpf_map_update_elem(map_fd, &i, &sfd[i], BPF_ANY);
+ if (!err) {
+ printf("Failed sockmap update BPF_ANY\n");
+ goto out_sockmap;
+ }
+
+ err = bpf_map_update_elem(map_fd, &i, &sfd[i], BPF_EXIST);
+ if (!err) {
+ printf("Failed sockmap update BPF_EXIST\n");
+ goto out_sockmap;
+ }
+
+ /* Test map close sockets */
+ for (i = 0; i < 6; i++)
+ close(sfd[i]);
+ close(fd);
+ close(map_fd);
+ bpf_object__close(obj);
+ return;
+out:
+ for (i = 0; i < 6; i++)
+ close(sfd[i]);
+ printf("Failed to create sockmap '%i:%s'!\n", i, strerror(errno));
+ exit(1);
+out_sockmap:
+ for (i = 0; i < 6; i++)
+ close(sfd[i]);
+ close(fd);
+ exit(1);
+}
+
#define MAP_SIZE (32 * 1024)
static void test_map_large(void)
@@ -621,6 +928,7 @@ static void run_all_tests(void)
test_arraymap_percpu_many_keys();
test_devmap(0, NULL);
+ test_sockmap(0, NULL);
test_map_large();
test_map_parallel();
diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
index 1f7dd35..1cb0378 100644
--- a/tools/testing/selftests/bpf/test_progs.c
+++ b/tools/testing/selftests/bpf/test_progs.c
@@ -75,39 +75,6 @@
__ret; \
})
-static int bpf_prog_load(const char *file, enum bpf_prog_type type,
- struct bpf_object **pobj, int *prog_fd)
-{
- struct bpf_program *prog;
- struct bpf_object *obj;
- int err;
-
- obj = bpf_object__open(file);
- if (IS_ERR(obj)) {
- error_cnt++;
- return -ENOENT;
- }
-
- prog = bpf_program__next(NULL, obj);
- if (!prog) {
- bpf_object__close(obj);
- error_cnt++;
- return -ENOENT;
- }
-
- bpf_program__set_type(prog, type);
- err = bpf_object__load(obj);
- if (err) {
- bpf_object__close(obj);
- error_cnt++;
- return -EINVAL;
- }
-
- *pobj = obj;
- *prog_fd = bpf_program__fd(prog);
- return 0;
-}
-
static int bpf_find_map(const char *test, struct bpf_object *obj,
const char *name)
{
@@ -130,8 +97,10 @@ static void test_pkt_access(void)
int err, prog_fd;
err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
- if (err)
+ if (err) {
+ error_cnt++;
return;
+ }
err = bpf_prog_test_run(prog_fd, 100000, &pkt_v4, sizeof(pkt_v4),
NULL, NULL, &retval, &duration);
@@ -162,8 +131,10 @@ static void test_xdp(void)
int err, prog_fd, map_fd;
err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
- if (err)
+ if (err) {
+ error_cnt++;
return;
+ }
map_fd = bpf_find_map(__func__, obj, "vip2tnl");
if (map_fd < 0)
@@ -223,8 +194,10 @@ static void test_l4lb(void)
u32 *magic = (u32 *)buf;
err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
- if (err)
+ if (err) {
+ error_cnt++;
return;
+ }
map_fd = bpf_find_map(__func__, obj, "vip_map");
if (map_fd < 0)
@@ -280,8 +253,10 @@ static void test_tcp_estats(void)
err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd);
CHECK(err, "", "err %d errno %d\n", err, errno);
- if (err)
+ if (err) {
+ error_cnt++;
return;
+ }
bpf_object__close(obj);
}
@@ -336,6 +311,8 @@ static void test_bpf_obj_id(void)
/* test_obj_id.o is a dumb prog. It should never fail
* to load.
*/
+ if (err)
+ error_cnt++;
assert(!err);
/* Check getting prog info */
@@ -496,8 +473,10 @@ static void test_pkt_md_access(void)
int err, prog_fd;
err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
- if (err)
+ if (err) {
+ error_cnt++;
return;
+ }
err = bpf_prog_test_run(prog_fd, 10, &pkt_v4, sizeof(pkt_v4),
NULL, NULL, &retval, &duration);
^ permalink raw reply related
* [net-next PATCH 09/10] bpf: selftests: add tests for new __sk_buff members
From: John Fastabend @ 2017-08-16 5:33 UTC (permalink / raw)
To: davem, daniel, ast; +Cc: tgraf, netdev, john.fastabend, tom
In-Reply-To: <20170816052338.15445.83732.stgit@john-Precision-Tower-5810>
This adds tests to access new __sk_buff members from sk skb program
type.
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
tools/testing/selftests/bpf/test_verifier.c | 152 +++++++++++++++++++++++++++
1 file changed, 152 insertions(+)
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
index 1b76712..c03542c 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -967,6 +967,158 @@ struct test_val {
.result = REJECT,
},
{
+ "invalid access __sk_buff family",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, family)),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "invalid bpf_context access",
+ .result = REJECT,
+ },
+ {
+ "invalid access __sk_buff remote_ip4",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, remote_ip4)),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "invalid bpf_context access",
+ .result = REJECT,
+ },
+ {
+ "invalid access __sk_buff local_ip4",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, local_ip4)),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "invalid bpf_context access",
+ .result = REJECT,
+ },
+ {
+ "invalid access __sk_buff remote_ip6",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, remote_ip6)),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "invalid bpf_context access",
+ .result = REJECT,
+ },
+ {
+ "invalid access __sk_buff local_ip6",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, local_ip6)),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "invalid bpf_context access",
+ .result = REJECT,
+ },
+ {
+ "invalid access __sk_buff remote_port",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, remote_port)),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "invalid bpf_context access",
+ .result = REJECT,
+ },
+ {
+ "invalid access __sk_buff remote_port",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, local_port)),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "invalid bpf_context access",
+ .result = REJECT,
+ },
+ {
+ "valid access __sk_buff family",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, family)),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_SK_SKB,
+ },
+ {
+ "valid access __sk_buff remote_ip4",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, remote_ip4)),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_SK_SKB,
+ },
+ {
+ "valid access __sk_buff local_ip4",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, local_ip4)),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_SK_SKB,
+ },
+ {
+ "valid access __sk_buff remote_ip6",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, remote_ip6[0])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, remote_ip6[1])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, remote_ip6[2])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, remote_ip6[3])),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_SK_SKB,
+ },
+ {
+ "valid access __sk_buff local_ip6",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, local_ip6[0])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, local_ip6[1])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, local_ip6[2])),
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, local_ip6[3])),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_SK_SKB,
+ },
+ {
+ "valid access __sk_buff remote_port",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, remote_port)),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_SK_SKB,
+ },
+ {
+ "valid access __sk_buff remote_port",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+ offsetof(struct __sk_buff, local_port)),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_SK_SKB,
+ },
+ {
"check skb->mark is not writeable by sockets",
.insns = {
BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_1,
^ permalink raw reply related
* [net-next PATCH 08/10] bpf: sockmap sample program
From: John Fastabend @ 2017-08-16 5:33 UTC (permalink / raw)
To: davem, daniel, ast; +Cc: tgraf, netdev, john.fastabend, tom
In-Reply-To: <20170816052338.15445.83732.stgit@john-Precision-Tower-5810>
This program binds a program to a cgroup and then matches hard
coded IP addresses and adds these to a sockmap.
This will receive messages from the backend and send them to
the client.
client:X <---> frontend:10000 client:X <---> backend:10001
To keep things simple this is only designed for 1:1 connections
using hard coded values. A more complete example would allow many
backends and clients.
To run,
# sockmap <cgroup2_dir>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
samples/bpf/bpf_load.c | 8 +
samples/sockmap/Makefile | 78 ++++++++
samples/sockmap/sockmap_kern.c | 110 +++++++++++
samples/sockmap/sockmap_user.c | 286 +++++++++++++++++++++++++++++
tools/include/uapi/linux/bpf.h | 46 +++++
tools/lib/bpf/bpf.c | 14 +
tools/lib/bpf/bpf.h | 4
tools/testing/selftests/bpf/bpf_helpers.h | 7 +
8 files changed, 547 insertions(+), 6 deletions(-)
create mode 100644 samples/sockmap/Makefile
create mode 100644 samples/sockmap/sockmap_kern.c
create mode 100644 samples/sockmap/sockmap_user.c
diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index 899f403..a8552b8 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -65,6 +65,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
bool is_cgroup_skb = strncmp(event, "cgroup/skb", 10) == 0;
bool is_cgroup_sk = strncmp(event, "cgroup/sock", 11) == 0;
bool is_sockops = strncmp(event, "sockops", 7) == 0;
+ bool is_sk_skb = strncmp(event, "sk_skb", 6) == 0;
size_t insns_cnt = size / sizeof(struct bpf_insn);
enum bpf_prog_type prog_type;
char buf[256];
@@ -92,6 +93,8 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
prog_type = BPF_PROG_TYPE_CGROUP_SOCK;
} else if (is_sockops) {
prog_type = BPF_PROG_TYPE_SOCK_OPS;
+ } else if (is_sk_skb) {
+ prog_type = BPF_PROG_TYPE_SK_SKB;
} else {
printf("Unknown event '%s'\n", event);
return -1;
@@ -109,7 +112,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
if (is_xdp || is_perf_event || is_cgroup_skb || is_cgroup_sk)
return 0;
- if (is_socket || is_sockops) {
+ if (is_socket || is_sockops || is_sk_skb) {
if (is_socket)
event += 6;
else
@@ -567,7 +570,8 @@ static int do_load_bpf_file(const char *path, fixup_map_cb fixup_map)
memcmp(shname, "perf_event", 10) == 0 ||
memcmp(shname, "socket", 6) == 0 ||
memcmp(shname, "cgroup/", 7) == 0 ||
- memcmp(shname, "sockops", 7) == 0) {
+ memcmp(shname, "sockops", 7) == 0 ||
+ memcmp(shname, "sk_skb", 6) == 0) {
ret = load_and_attach(shname, data->d_buf,
data->d_size);
if (ret != 0)
diff --git a/samples/sockmap/Makefile b/samples/sockmap/Makefile
new file mode 100644
index 0000000..9291ab8
--- /dev/null
+++ b/samples/sockmap/Makefile
@@ -0,0 +1,78 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+# List of programs to build
+hostprogs-y := sockmap
+
+# Libbpf dependencies
+LIBBPF := ../../tools/lib/bpf/bpf.o
+
+HOSTCFLAGS += -I$(objtree)/usr/include
+HOSTCFLAGS += -I$(srctree)/tools/lib/
+HOSTCFLAGS += -I$(srctree)/tools/testing/selftests/bpf/
+HOSTCFLAGS += -I$(srctree)/tools/lib/ -I$(srctree)/tools/include
+HOSTCFLAGS += -I$(srctree)/tools/perf
+
+sockmap-objs := ../bpf/bpf_load.o $(LIBBPF) sockmap_user.o
+
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
+always += sockmap_kern.o
+
+HOSTLOADLIBES_sockmap += -lelf -lpthread
+
+# Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline:
+# make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang
+LLC ?= llc
+CLANG ?= clang
+
+# Trick to allow make to be run from this directory
+all:
+ $(MAKE) -C ../../ $(CURDIR)/
+
+clean:
+ $(MAKE) -C ../../ M=$(CURDIR) clean
+ @rm -f *~
+
+$(obj)/syscall_nrs.s: $(src)/syscall_nrs.c
+ $(call if_changed_dep,cc_s_c)
+
+$(obj)/syscall_nrs.h: $(obj)/syscall_nrs.s FORCE
+ $(call filechk,offsets,__SYSCALL_NRS_H__)
+
+clean-files += syscall_nrs.h
+
+FORCE:
+
+
+# Verify LLVM compiler tools are available and bpf target is supported by llc
+.PHONY: verify_cmds verify_target_bpf $(CLANG) $(LLC)
+
+verify_cmds: $(CLANG) $(LLC)
+ @for TOOL in $^ ; do \
+ if ! (which -- "$${TOOL}" > /dev/null 2>&1); then \
+ echo "*** ERROR: Cannot find LLVM tool $${TOOL}" ;\
+ exit 1; \
+ else true; fi; \
+ done
+
+verify_target_bpf: verify_cmds
+ @if ! (${LLC} -march=bpf -mattr=help > /dev/null 2>&1); then \
+ echo "*** ERROR: LLVM (${LLC}) does not support 'bpf' target" ;\
+ echo " NOTICE: LLVM version >= 3.7.1 required" ;\
+ exit 2; \
+ else true; fi
+
+$(src)/*.c: verify_target_bpf
+
+# asm/sysreg.h - inline assembly used by it is incompatible with llvm.
+# But, there is no easy way to fix it, so just exclude it since it is
+# useless for BPF samples.
+$(obj)/%.o: $(src)/%.c
+ $(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) -I$(obj) \
+ -D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
+ -Wno-compare-distinct-pointer-types \
+ -Wno-gnu-variable-sized-type-not-at-end \
+ -Wno-address-of-packed-member -Wno-tautological-compare \
+ -Wno-unknown-warning-option \
+ -O2 -emit-llvm -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@
diff --git a/samples/sockmap/sockmap_kern.c b/samples/sockmap/sockmap_kern.c
new file mode 100644
index 0000000..6ff986f
--- /dev/null
+++ b/samples/sockmap/sockmap_kern.c
@@ -0,0 +1,110 @@
+/* Copyright (c) 2017 Covalent IO, Inc. http://covalent.io
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <uapi/linux/bpf.h>
+#include <uapi/linux/if_ether.h>
+#include <uapi/linux/if_packet.h>
+#include <uapi/linux/ip.h>
+#include "../../tools/testing/selftests/bpf/bpf_helpers.h"
+#include "../../tools/testing/selftests/bpf/bpf_endian.h"
+
+/* Sockmap sample program connects a client and a backend together
+ * using cgroups.
+ *
+ * client:X <---> frontend:80 client:X <---> backend:80
+ *
+ * For simplicity we hard code values here and bind 1:1. The hard
+ * coded values are part of the setup in sockmap.sh script that
+ * is associated with this BPF program.
+ *
+ * The bpf_printk is verbose and prints information as connections
+ * are established and verdicts are decided.
+ */
+
+#define bpf_printk(fmt, ...) \
+({ \
+ char ____fmt[] = fmt; \
+ bpf_trace_printk(____fmt, sizeof(____fmt), \
+ ##__VA_ARGS__); \
+})
+
+struct bpf_map_def SEC("maps") sock_map = {
+ .type = BPF_MAP_TYPE_SOCKMAP,
+ .key_size = sizeof(int),
+ .value_size = sizeof(int),
+ .max_entries = 20,
+};
+
+SEC("sk_skb1")
+int bpf_prog1(struct __sk_buff *skb)
+{
+ return skb->len;
+}
+
+SEC("sk_skb2")
+int bpf_prog2(struct __sk_buff *skb)
+{
+ __u32 lport = skb->local_port;
+ __u32 rport = skb->remote_port;
+ int ret = 0;
+
+ if (lport == 10000)
+ ret = 10;
+ else
+ ret = 1;
+
+ bpf_printk("sockmap: %d -> %d @ %d\n", lport, bpf_ntohl(rport), ret);
+ return bpf_sk_redirect_map(&sock_map, ret, 0);
+}
+
+SEC("sockops")
+int bpf_sockmap(struct bpf_sock_ops *skops)
+{
+ __u32 lport, rport;
+ int op, err = 0, index, key, ret;
+
+
+ op = (int) skops->op;
+
+ switch (op) {
+ case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
+ lport = skops->local_port;
+ rport = skops->remote_port;
+
+ if (lport == 10000) {
+ ret = 1;
+ err = bpf_sock_map_update(skops, &sock_map, &ret,
+ BPF_NOEXIST,
+ BPF_SOCKMAP_STRPARSER);
+ bpf_printk("passive(%i -> %i) map ctx update err: %d\n",
+ lport, bpf_ntohl(rport), err);
+ }
+ break;
+ case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
+ lport = skops->local_port;
+ rport = skops->remote_port;
+
+ if (bpf_ntohl(rport) == 10001) {
+ ret = 10;
+ err = bpf_sock_map_update(skops, &sock_map, &ret,
+ BPF_NOEXIST,
+ BPF_SOCKMAP_STRPARSER);
+ bpf_printk("active(%i -> %i) map ctx update err: %d\n",
+ lport, bpf_ntohl(rport), err);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+char _license[] SEC("license") = "GPL";
diff --git a/samples/sockmap/sockmap_user.c b/samples/sockmap/sockmap_user.c
new file mode 100644
index 0000000..fb78f5a
--- /dev/null
+++ b/samples/sockmap/sockmap_user.c
@@ -0,0 +1,286 @@
+/* Copyright (c) 2017 Covalent IO, Inc. http://covalent.io
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <fcntl.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <linux/netlink.h>
+#include <linux/socket.h>
+#include <linux/sock_diag.h>
+#include <linux/bpf.h>
+#include <linux/if_link.h>
+#include <assert.h>
+#include <libgen.h>
+
+#include "../bpf/bpf_load.h"
+#include "../bpf/bpf_util.h"
+#include "../bpf/libbpf.h"
+
+int running;
+void running_handler(int a);
+
+/* randomly selected ports for testing on lo */
+#define S1_PORT 10000
+#define S2_PORT 10001
+
+static int sockmap_test_sockets(int rate, int dot)
+{
+ int i, sc, err, max_fd, one = 1;
+ int s1, s2, c1, c2, p1, p2;
+ struct sockaddr_in addr;
+ struct timeval timeout;
+ char buf[1024] = {0};
+ int *fds[4] = {&s1, &s2, &c1, &c2};
+ fd_set w;
+
+ s1 = s2 = p1 = p2 = c1 = c2 = 0;
+
+ /* Init sockets */
+ for (i = 0; i < 4; i++) {
+ *fds[i] = socket(AF_INET, SOCK_STREAM, 0);
+ if (*fds[i] < 0) {
+ perror("socket s1 failed()");
+ err = *fds[i];
+ goto out;
+ }
+ }
+
+ /* Allow reuse */
+ for (i = 0; i < 2; i++) {
+ err = setsockopt(*fds[i], SOL_SOCKET, SO_REUSEADDR,
+ (char *)&one, sizeof(one));
+ if (err) {
+ perror("setsockopt failed()");
+ goto out;
+ }
+ }
+
+ /* Non-blocking sockets */
+ for (i = 0; i < 4; i++) {
+ err = ioctl(*fds[i], FIONBIO, (char *)&one);
+ if (err < 0) {
+ perror("ioctl s1 failed()");
+ goto out;
+ }
+ }
+
+ /* Bind server sockets */
+ memset(&addr, 0, sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ addr.sin_port = htons(S1_PORT);
+ err = bind(s1, (struct sockaddr *)&addr, sizeof(addr));
+ if (err < 0) {
+ perror("bind s1 failed()\n");
+ goto out;
+ }
+
+ addr.sin_port = htons(S2_PORT);
+ err = bind(s2, (struct sockaddr *)&addr, sizeof(addr));
+ if (err < 0) {
+ perror("bind s2 failed()\n");
+ goto out;
+ }
+
+ /* Listen server sockets */
+ addr.sin_port = htons(S1_PORT);
+ err = listen(s1, 32);
+ if (err < 0) {
+ perror("listen s1 failed()\n");
+ goto out;
+ }
+
+ addr.sin_port = htons(S2_PORT);
+ err = listen(s2, 32);
+ if (err < 0) {
+ perror("listen s1 failed()\n");
+ goto out;
+ }
+
+ /* Initiate Connect */
+ addr.sin_port = htons(S1_PORT);
+ err = connect(c1, (struct sockaddr *)&addr, sizeof(addr));
+ if (err < 0 && errno != EINPROGRESS) {
+ perror("connect c1 failed()\n");
+ goto out;
+ }
+
+ addr.sin_port = htons(S2_PORT);
+ err = connect(c2, (struct sockaddr *)&addr, sizeof(addr));
+ if (err < 0 && errno != EINPROGRESS) {
+ perror("connect c2 failed()\n");
+ goto out;
+ }
+
+ /* Accept Connecrtions */
+ p1 = accept(s1, NULL, NULL);
+ if (p1 < 0) {
+ perror("accept s1 failed()\n");
+ goto out;
+ }
+
+ p2 = accept(s2, NULL, NULL);
+ if (p2 < 0) {
+ perror("accept s1 failed()\n");
+ goto out;
+ }
+
+ max_fd = p2;
+ timeout.tv_sec = 10;
+ timeout.tv_usec = 0;
+
+ printf("connected sockets: c1 <-> p1, c2 <-> p2\n");
+ printf("cgroups binding: c1(%i) <-> s1(%i) - - - c2(%i) <-> s2(%i)\n",
+ c1, s1, c2, s2);
+
+ /* Ping/Pong data from client to server */
+ sc = send(c1, buf, sizeof(buf), 0);
+ if (sc < 0) {
+ perror("send failed()\n");
+ goto out;
+ }
+
+ do {
+ int s, rc, i;
+
+ /* FD sets */
+ FD_ZERO(&w);
+ FD_SET(c1, &w);
+ FD_SET(c2, &w);
+ FD_SET(p1, &w);
+ FD_SET(p2, &w);
+
+ s = select(max_fd + 1, &w, NULL, NULL, &timeout);
+ if (s == -1) {
+ perror("select()");
+ break;
+ } else if (!s) {
+ fprintf(stderr, "unexpected timeout\n");
+ break;
+ }
+
+ for (i = 0; i <= max_fd && s > 0; ++i) {
+ if (!FD_ISSET(i, &w))
+ continue;
+
+ s--;
+
+ rc = recv(i, buf, sizeof(buf), 0);
+ if (rc < 0) {
+ if (errno != EWOULDBLOCK) {
+ perror("recv failed()\n");
+ break;
+ }
+ }
+
+ if (rc == 0) {
+ close(i);
+ break;
+ }
+
+ sc = send(i, buf, rc, 0);
+ if (sc < 0) {
+ perror("send failed()\n");
+ break;
+ }
+ }
+ sleep(rate);
+ if (dot) {
+ printf(".");
+ fflush(stdout);
+
+ }
+ } while (running);
+
+out:
+ close(s1);
+ close(s2);
+ close(p1);
+ close(p2);
+ close(c1);
+ close(c2);
+ return err;
+}
+
+int main(int argc, char **argv)
+{
+ int rate = 1, dot = 1;
+ char filename[256];
+ int err, cg_fd;
+ char *cg_path;
+
+ cg_path = argv[argc - 1];
+ snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
+
+ running = 1;
+
+ /* catch SIGINT */
+ signal(SIGINT, running_handler);
+
+ if (load_bpf_file(filename)) {
+ fprintf(stderr, "load_bpf_file: (%s) %s\n",
+ filename, strerror(errno));
+ return 1;
+ }
+
+ /* Cgroup configuration */
+ cg_fd = open(cg_path, O_DIRECTORY, O_RDONLY);
+ if (cg_fd < 0) {
+ fprintf(stderr, "ERROR: (%i) open cg path failed: %s\n",
+ cg_fd, cg_path);
+ return cg_fd;
+ }
+
+ /* Attach programs to sockmap */
+ err = __bpf_prog_attach(prog_fd[0], prog_fd[1], map_fd[0],
+ BPF_CGROUP_SMAP_INGRESS, 0);
+ if (err) {
+ fprintf(stderr, "ERROR: bpf_prog_attach (sockmap): %d (%s)\n",
+ err, strerror(errno));
+ return err;
+ }
+
+ /* Attach to cgroups */
+ err = bpf_prog_attach(prog_fd[2], cg_fd, BPF_CGROUP_SOCK_OPS, 0);
+ if (err) {
+ fprintf(stderr, "ERROR: bpf_prog_attach (groups): %d (%s)\n",
+ err, strerror(errno));
+ return err;
+ }
+
+ err = sockmap_test_sockets(rate, dot);
+ if (err) {
+ fprintf(stderr, "ERROR: test socket failed: %d\n", err);
+ return err;
+ }
+ return 0;
+}
+
+void running_handler(int a)
+{
+ running = 0;
+}
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index bf3b2e2..2d97dd2 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -110,6 +110,7 @@ enum bpf_map_type {
BPF_MAP_TYPE_ARRAY_OF_MAPS,
BPF_MAP_TYPE_HASH_OF_MAPS,
BPF_MAP_TYPE_DEVMAP,
+ BPF_MAP_TYPE_SOCKMAP,
};
enum bpf_prog_type {
@@ -127,6 +128,7 @@ enum bpf_prog_type {
BPF_PROG_TYPE_LWT_OUT,
BPF_PROG_TYPE_LWT_XMIT,
BPF_PROG_TYPE_SOCK_OPS,
+ BPF_PROG_TYPE_SK_SKB,
};
enum bpf_attach_type {
@@ -134,11 +136,18 @@ enum bpf_attach_type {
BPF_CGROUP_INET_EGRESS,
BPF_CGROUP_INET_SOCK_CREATE,
BPF_CGROUP_SOCK_OPS,
+ BPF_CGROUP_SMAP_INGRESS,
__MAX_BPF_ATTACH_TYPE
};
#define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE
+enum bpf_sockmap_flags {
+ BPF_SOCKMAP_UNSPEC,
+ BPF_SOCKMAP_STRPARSER,
+ __MAX_BPF_SOCKMAP_FLAG
+};
+
/* If BPF_F_ALLOW_OVERRIDE flag is used in BPF_PROG_ATTACH command
* to the given target_fd cgroup the descendent cgroup will be able to
* override effective bpf program that was inherited from this cgroup
@@ -210,6 +219,7 @@ enum bpf_attach_type {
__u32 attach_bpf_fd; /* eBPF program to attach */
__u32 attach_type;
__u32 attach_flags;
+ __u32 attach_bpf_fd2;
};
struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
@@ -545,6 +555,23 @@ enum bpf_attach_type {
* @mode: operation mode (enum bpf_adj_room_mode)
* @flags: reserved for future use
* Return: 0 on success or negative error code
+ *
+ * int bpf_sk_redirect_map(map, key, flags)
+ * Redirect skb to a sock in map using key as a lookup key for the
+ * sock in map.
+ * @map: pointer to sockmap
+ * @key: key to lookup sock in map
+ * @flags: reserved for future use
+ * Return: SK_REDIRECT
+ *
+ * int bpf_sock_map_update(skops, map, key, flags, map_flags)
+ * @skops: pointer to bpf_sock_ops
+ * @map: pointer to sockmap to update
+ * @key: key to insert/update sock in map
+ * @flags: same flags as map update elem
+ * @map_flags: sock map specific flags
+ * bit 1: Enable strparser
+ * other bits: reserved
*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
@@ -598,7 +625,9 @@ enum bpf_attach_type {
FN(set_hash), \
FN(setsockopt), \
FN(skb_adjust_room), \
- FN(redirect_map),
+ FN(redirect_map), \
+ FN(sk_redirect_map), \
+ FN(sock_map_update),
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call
@@ -675,6 +704,15 @@ struct __sk_buff {
__u32 data;
__u32 data_end;
__u32 napi_id;
+
+ /* accessed by BPF_PROG_TYPE_sk_skb types */
+ __u32 family;
+ __u32 remote_ip4; /* Stored in network byte order */
+ __u32 local_ip4; /* Stored in network byte order */
+ __u32 remote_ip6[4]; /* Stored in network byte order */
+ __u32 local_ip6[4]; /* Stored in network byte order */
+ __u32 remote_port; /* Stored in network byte order */
+ __u32 local_port; /* stored in host byte order */
};
struct bpf_tunnel_key {
@@ -734,6 +772,12 @@ struct xdp_md {
__u32 data_end;
};
+enum sk_action {
+ SK_ABORTED = 0,
+ SK_DROP,
+ SK_REDIRECT,
+};
+
#define BPF_TAG_SIZE 8
struct bpf_prog_info {
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index e5bbb09..7766015 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -211,20 +211,28 @@ int bpf_obj_get(const char *pathname)
return sys_bpf(BPF_OBJ_GET, &attr, sizeof(attr));
}
-int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type,
- unsigned int flags)
+int __bpf_prog_attach(int prog_fd1, int prog_fd2, int target_fd,
+ enum bpf_attach_type type,
+ unsigned int flags)
{
union bpf_attr attr;
bzero(&attr, sizeof(attr));
attr.target_fd = target_fd;
- attr.attach_bpf_fd = prog_fd;
+ attr.attach_bpf_fd = prog_fd1;
+ attr.attach_bpf_fd2 = prog_fd2;
attr.attach_type = type;
attr.attach_flags = flags;
return sys_bpf(BPF_PROG_ATTACH, &attr, sizeof(attr));
}
+int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type,
+ unsigned int flags)
+{
+ return __bpf_prog_attach(prog_fd, 0, target_fd, type, flags);
+}
+
int bpf_prog_detach(int target_fd, enum bpf_attach_type type)
{
union bpf_attr attr;
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 418c86e..eaee585 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -50,6 +50,10 @@ int bpf_map_update_elem(int fd, const void *key, const void *value,
int bpf_obj_get(const char *pathname);
int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type,
unsigned int flags);
+int __bpf_prog_attach(int prog1, int prog2,
+ int attachable_fd,
+ enum bpf_attach_type type,
+ unsigned int flags);
int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type);
int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size,
void *data_out, __u32 *size_out, __u32 *retval,
diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h
index acbd605..73092d4 100644
--- a/tools/testing/selftests/bpf/bpf_helpers.h
+++ b/tools/testing/selftests/bpf/bpf_helpers.h
@@ -65,6 +65,13 @@ static int (*bpf_xdp_adjust_head)(void *ctx, int offset) =
static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval,
int optlen) =
(void *) BPF_FUNC_setsockopt;
+static int (*bpf_sk_redirect_map)(void *map, int key, int flags) =
+ (void *) BPF_FUNC_sk_redirect_map;
+static int (*bpf_sock_map_update)(void *map, void *key, void *value,
+ unsigned long long flags,
+ unsigned long long map_lags) =
+ (void *) BPF_FUNC_sock_map_update;
+
/* llvm builtin functions that eBPF C program may use to
* emit BPF_LD_ABS and BPF_LD_IND instructions
^ permalink raw reply related
* [net-next PATCH 07/10] bpf: add access to sock fields and pkt data from sk_skb programs
From: John Fastabend @ 2017-08-16 5:33 UTC (permalink / raw)
To: davem, daniel, ast; +Cc: tgraf, netdev, john.fastabend, tom
In-Reply-To: <20170816052338.15445.83732.stgit@john-Precision-Tower-5810>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
include/uapi/linux/bpf.h | 9 ++
kernel/bpf/verifier.c | 1
net/core/filter.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 179 insertions(+)
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 7f77476..5ecbe81 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -712,6 +712,15 @@ struct __sk_buff {
__u32 data;
__u32 data_end;
__u32 napi_id;
+
+ /* accessed by BPF_PROG_TYPE_sk_skb types */
+ __u32 family;
+ __u32 remote_ip4; /* Stored in network byte order */
+ __u32 local_ip4; /* Stored in network byte order */
+ __u32 remote_ip6[4]; /* Stored in network byte order */
+ __u32 local_ip6[4]; /* Stored in network byte order */
+ __u32 remote_port; /* Stored in network byte order */
+ __u32 local_port; /* stored in host byte order */
};
struct bpf_tunnel_key {
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index a439ad5..bfed82e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -848,6 +848,7 @@ static bool may_access_direct_pkt_data(struct bpf_verifier_env *env,
case BPF_PROG_TYPE_SCHED_ACT:
case BPF_PROG_TYPE_XDP:
case BPF_PROG_TYPE_LWT_XMIT:
+ case BPF_PROG_TYPE_SK_SKB:
if (meta)
return meta->pkt_access;
diff --git a/net/core/filter.c b/net/core/filter.c
index 934b92f..9a9e31f 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -3278,8 +3278,16 @@ static unsigned long bpf_xdp_copy(void *dst_buff, const void *src_buff,
static const struct bpf_func_proto *sk_skb_func_proto(enum bpf_func_id func_id)
{
switch (func_id) {
+ case BPF_FUNC_skb_store_bytes:
+ return &bpf_skb_store_bytes_proto;
case BPF_FUNC_skb_load_bytes:
return &bpf_skb_load_bytes_proto;
+ case BPF_FUNC_skb_pull_data:
+ return &bpf_skb_pull_data_proto;
+ case BPF_FUNC_skb_change_tail:
+ return &bpf_skb_change_tail_proto;
+ case BPF_FUNC_skb_change_head:
+ return &bpf_skb_change_head_proto;
case BPF_FUNC_get_socket_cookie:
return &bpf_get_socket_cookie_proto;
case BPF_FUNC_get_socket_uid:
@@ -3343,6 +3351,10 @@ static bool bpf_skb_is_valid_access(int off, int size, enum bpf_access_type type
if (off + size > offsetofend(struct __sk_buff, cb[4]))
return false;
break;
+ case bpf_ctx_range_till(struct __sk_buff, remote_ip6[0], remote_ip6[3]):
+ case bpf_ctx_range_till(struct __sk_buff, local_ip6[0], local_ip6[3]):
+ case bpf_ctx_range_till(struct __sk_buff, remote_ip4, remote_ip4):
+ case bpf_ctx_range_till(struct __sk_buff, local_ip4, local_ip4):
case bpf_ctx_range(struct __sk_buff, data):
case bpf_ctx_range(struct __sk_buff, data_end):
if (size != size_default)
@@ -3371,6 +3383,7 @@ static bool sk_filter_is_valid_access(int off, int size,
case bpf_ctx_range(struct __sk_buff, tc_classid):
case bpf_ctx_range(struct __sk_buff, data):
case bpf_ctx_range(struct __sk_buff, data_end):
+ case bpf_ctx_range_till(struct __sk_buff, family, local_port):
return false;
}
@@ -3392,6 +3405,7 @@ static bool lwt_is_valid_access(int off, int size,
{
switch (off) {
case bpf_ctx_range(struct __sk_buff, tc_classid):
+ case bpf_ctx_range_till(struct __sk_buff, family, local_port):
return false;
}
@@ -3505,6 +3519,8 @@ static bool tc_cls_act_is_valid_access(int off, int size,
case bpf_ctx_range(struct __sk_buff, data_end):
info->reg_type = PTR_TO_PACKET_END;
break;
+ case bpf_ctx_range_till(struct __sk_buff, family, local_port):
+ return false;
}
return bpf_skb_is_valid_access(off, size, type, info);
@@ -3582,11 +3598,63 @@ static bool sock_ops_is_valid_access(int off, int size,
return __is_valid_sock_ops_access(off, size);
}
+static int sk_skb_prologue(struct bpf_insn *insn_buf, bool direct_write,
+ const struct bpf_prog *prog)
+{
+ struct bpf_insn *insn = insn_buf;
+
+ if (!direct_write)
+ return 0;
+
+ /* if (!skb->cloned)
+ * goto start;
+ *
+ * (Fast-path, otherwise approximation that we might be
+ * a clone, do the rest in helper.)
+ */
+ *insn++ = BPF_LDX_MEM(BPF_B, BPF_REG_6, BPF_REG_1, CLONED_OFFSET());
+ *insn++ = BPF_ALU32_IMM(BPF_AND, BPF_REG_6, CLONED_MASK);
+ *insn++ = BPF_JMP_IMM(BPF_JEQ, BPF_REG_6, 0, 7);
+
+ /* ret = bpf_skb_pull_data(skb, 0); */
+ *insn++ = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1);
+ *insn++ = BPF_ALU64_REG(BPF_XOR, BPF_REG_2, BPF_REG_2);
+ *insn++ = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+ BPF_FUNC_skb_pull_data);
+ /* if (!ret)
+ * goto restore;
+ * return SK_DROP;
+ */
+ *insn++ = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2);
+ *insn++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, SK_DROP);
+ *insn++ = BPF_EXIT_INSN();
+
+ /* restore: */
+ *insn++ = BPF_MOV64_REG(BPF_REG_1, BPF_REG_6);
+ /* start: */
+ *insn++ = prog->insnsi[0];
+
+ return insn - insn_buf;
+}
+
static bool sk_skb_is_valid_access(int off, int size,
enum bpf_access_type type,
struct bpf_insn_access_aux *info)
{
+ if (type == BPF_WRITE) {
+ switch (off) {
+ case bpf_ctx_range(struct __sk_buff, mark):
+ case bpf_ctx_range(struct __sk_buff, tc_index):
+ case bpf_ctx_range(struct __sk_buff, priority):
+ break;
+ default:
+ return false;
+ }
+ }
+
switch (off) {
+ case bpf_ctx_range(struct __sk_buff, tc_classid):
+ return false;
case bpf_ctx_range(struct __sk_buff, data):
info->reg_type = PTR_TO_PACKET;
break;
@@ -3781,6 +3849,106 @@ static u32 bpf_convert_ctx_access(enum bpf_access_type type,
*insn++ = BPF_MOV64_IMM(si->dst_reg, 0);
#endif
break;
+ case offsetof(struct __sk_buff, family):
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_family) != 2);
+
+ *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, sk),
+ si->dst_reg, si->src_reg,
+ offsetof(struct sk_buff, sk));
+ *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg,
+ bpf_target_off(struct sock_common,
+ skc_family,
+ 2, target_size));
+ break;
+ case offsetof(struct __sk_buff, remote_ip4):
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_daddr) != 4);
+
+ *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, sk),
+ si->dst_reg, si->src_reg,
+ offsetof(struct sk_buff, sk));
+ *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg,
+ bpf_target_off(struct sock_common,
+ skc_daddr,
+ 4, target_size));
+ break;
+ case offsetof(struct __sk_buff, local_ip4):
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common,
+ skc_rcv_saddr) != 4);
+
+ *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, sk),
+ si->dst_reg, si->src_reg,
+ offsetof(struct sk_buff, sk));
+ *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg,
+ bpf_target_off(struct sock_common,
+ skc_rcv_saddr,
+ 4, target_size));
+ break;
+ case offsetof(struct __sk_buff, remote_ip6[0]) ...
+ offsetof(struct __sk_buff, remote_ip6[3]):
+#if IS_ENABLED(CONFIG_IPV6)
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common,
+ skc_v6_daddr.s6_addr32[0]) != 4);
+
+ off = si->off;
+ off -= offsetof(struct __sk_buff, remote_ip6[0]);
+
+ *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, sk),
+ si->dst_reg, si->src_reg,
+ offsetof(struct sk_buff, sk));
+ *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg,
+ offsetof(struct sock_common,
+ skc_v6_daddr.s6_addr32[0]) +
+ off);
+#else
+ *insn++ = BPF_MOV32_IMM(si->dst_reg, 0);
+#endif
+ break;
+ case offsetof(struct __sk_buff, local_ip6[0]) ...
+ offsetof(struct __sk_buff, local_ip6[3]):
+#if IS_ENABLED(CONFIG_IPV6)
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common,
+ skc_v6_rcv_saddr.s6_addr32[0]) != 4);
+
+ off = si->off;
+ off -= offsetof(struct __sk_buff, local_ip6[0]);
+
+ *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, sk),
+ si->dst_reg, si->src_reg,
+ offsetof(struct sk_buff, sk));
+ *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg,
+ offsetof(struct sock_common,
+ skc_v6_rcv_saddr.s6_addr32[0]) +
+ off);
+#else
+ *insn++ = BPF_MOV32_IMM(si->dst_reg, 0);
+#endif
+ break;
+
+ case offsetof(struct __sk_buff, remote_port):
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_dport) != 2);
+
+ *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, sk),
+ si->dst_reg, si->src_reg,
+ offsetof(struct sk_buff, sk));
+ *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg,
+ bpf_target_off(struct sock_common,
+ skc_dport,
+ 2, target_size));
+#ifndef __BIG_ENDIAN_BITFIELD
+ *insn++ = BPF_ALU32_IMM(BPF_LSH, si->dst_reg, 16);
+#endif
+ break;
+
+ case offsetof(struct __sk_buff, local_port):
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_num) != 2);
+
+ *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, sk),
+ si->dst_reg, si->src_reg,
+ offsetof(struct sk_buff, sk));
+ *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg,
+ bpf_target_off(struct sock_common,
+ skc_num, 2, target_size));
+ break;
}
return insn - insn_buf;
@@ -4069,6 +4237,7 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type,
.get_func_proto = sk_skb_func_proto,
.is_valid_access = sk_skb_is_valid_access,
.convert_ctx_access = bpf_convert_ctx_access,
+ .gen_prologue = sk_skb_prologue,
};
int sk_detach_filter(struct sock *sk)
^ permalink raw reply related
* [net-next PATCH 06/10] bpf: sockmap with sk redirect support
From: John Fastabend @ 2017-08-16 5:32 UTC (permalink / raw)
To: davem, daniel, ast; +Cc: tgraf, netdev, john.fastabend, tom
In-Reply-To: <20170816052338.15445.83732.stgit@john-Precision-Tower-5810>
Recently we added a new map type called dev map used to forward XDP
packets between ports (6093ec2dc313). This patches introduces a
similar notion for sockets.
A sockmap allows users to add participating sockets to a map. When
sockets are added to the map enough context is stored with the
map entry to use the entry with a new helper
bpf_sk_redirect_map(map, key, flags)
This helper (analogous to bpf_redirect_map in XDP) is given the map
and an entry in the map. When called from a sockmap program, discussed
below, the skb will be sent on the socket using skb_send_sock().
With the above we need a bpf program to call the helper from that will
then implement the send logic. The initial site implemented in this
series is the recv_sock hook. For this to work we implemented a map
attach command to add attributes to a map. In sockmap we add two
programs a parse program and a verdict program. The parse program
uses strparser to build messages and pass them to the verdict program.
The parse programs use the normal strparser semantics. The verdict
program is of type SK_SKB.
The verdict program returns a verdict SK_DROP, or SK_REDIRECT for
now. Additional actions may be added later. When SK_REDIRECT is
returned, expected when bpf program uses bpf_sk_redirect_map(), the
sockmap logic will consult per cpu variables set by the helper routine
and pull the sock entry out of the sock map. This pattern follows the
existing redirect logic in cls and xdp programs.
This gives the flow,
recv_sock -> str_parser (parse_prog) -> verdict_prog -> skb_send_sock
\
-> kfree_skb
As an example use case a message based load balancer may use specific
logic in the verdict program to select the sock to send on.
Sample programs are provided in future patches that hopefully illustrate
the user interfaces. Also selftests are in follow-on patches.
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
include/linux/bpf.h | 7
include/linux/bpf_types.h | 1
include/linux/filter.h | 2
include/uapi/linux/bpf.h | 33 ++
kernel/bpf/Makefile | 2
kernel/bpf/sockmap.c | 792 +++++++++++++++++++++++++++++++++++++++++++++
kernel/bpf/syscall.c | 51 +++
kernel/bpf/verifier.c | 14 +
net/core/filter.c | 43 ++
9 files changed, 940 insertions(+), 5 deletions(-)
create mode 100644 kernel/bpf/sockmap.c
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index d6e1de8..a4145e9 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -16,6 +16,7 @@
#include <linux/rbtree_latch.h>
struct perf_event;
+struct bpf_prog;
struct bpf_map;
/* map is generic key/value storage optionally accesible by eBPF programs */
@@ -37,6 +38,8 @@ struct bpf_map_ops {
void (*map_fd_put_ptr)(void *ptr);
u32 (*map_gen_lookup)(struct bpf_map *map, struct bpf_insn *insn_buf);
u32 (*map_fd_sys_lookup_elem)(void *ptr);
+ int (*map_attach)(struct bpf_map *map,
+ struct bpf_prog *p1, struct bpf_prog *p2);
};
struct bpf_map {
@@ -138,8 +141,6 @@ enum bpf_reg_type {
PTR_TO_PACKET_END, /* skb->data + headlen */
};
-struct bpf_prog;
-
/* The information passed from prog-specific *_is_valid_access
* back to the verifier.
*/
@@ -312,6 +313,7 @@ static inline void bpf_long_memcpy(void *dst, const void *src, u32 size)
/* Map specifics */
struct net_device *__dev_map_lookup_elem(struct bpf_map *map, u32 key);
+struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key);
void __dev_map_insert_ctx(struct bpf_map *map, u32 index);
void __dev_map_flush(struct bpf_map *map);
@@ -391,6 +393,7 @@ static inline void __dev_map_flush(struct bpf_map *map)
extern const struct bpf_func_proto bpf_skb_vlan_push_proto;
extern const struct bpf_func_proto bpf_skb_vlan_pop_proto;
extern const struct bpf_func_proto bpf_get_stackid_proto;
+extern const struct bpf_func_proto bpf_sock_map_update_proto;
/* Shared helpers among cBPF and eBPF. */
void bpf_user_rnd_init_once(void);
diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h
index 4b72db3..fa80507 100644
--- a/include/linux/bpf_types.h
+++ b/include/linux/bpf_types.h
@@ -38,4 +38,5 @@
BPF_MAP_TYPE(BPF_MAP_TYPE_HASH_OF_MAPS, htab_of_maps_map_ops)
#ifdef CONFIG_NET
BPF_MAP_TYPE(BPF_MAP_TYPE_DEVMAP, dev_map_ops)
+BPF_MAP_TYPE(BPF_MAP_TYPE_SOCKMAP, sock_map_ops)
#endif
diff --git a/include/linux/filter.h b/include/linux/filter.h
index d19ed3c..7015116 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -727,6 +727,8 @@ int xdp_do_redirect(struct net_device *dev,
void bpf_warn_invalid_xdp_action(u32 act);
void bpf_warn_invalid_xdp_redirect(u32 ifindex);
+struct sock *do_sk_redirect_map(void);
+
#ifdef CONFIG_BPF_JIT
extern int bpf_jit_enable;
extern int bpf_jit_harden;
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 2e796e3..7f77476 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -110,6 +110,7 @@ enum bpf_map_type {
BPF_MAP_TYPE_ARRAY_OF_MAPS,
BPF_MAP_TYPE_HASH_OF_MAPS,
BPF_MAP_TYPE_DEVMAP,
+ BPF_MAP_TYPE_SOCKMAP,
};
enum bpf_prog_type {
@@ -135,11 +136,15 @@ enum bpf_attach_type {
BPF_CGROUP_INET_EGRESS,
BPF_CGROUP_INET_SOCK_CREATE,
BPF_CGROUP_SOCK_OPS,
+ BPF_CGROUP_SMAP_INGRESS,
__MAX_BPF_ATTACH_TYPE
};
#define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE
+/* If BPF_SOCKMAP_STRPARSER is used sockmap will use strparser on receive */
+#define BPF_SOCKMAP_STRPARSER (1U << 0)
+
/* If BPF_F_ALLOW_OVERRIDE flag is used in BPF_PROG_ATTACH command
* to the given target_fd cgroup the descendent cgroup will be able to
* override effective bpf program that was inherited from this cgroup
@@ -211,6 +216,7 @@ enum bpf_attach_type {
__u32 attach_bpf_fd; /* eBPF program to attach */
__u32 attach_type;
__u32 attach_flags;
+ __u32 attach_bpf_fd2;
};
struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
@@ -557,6 +563,23 @@ enum bpf_attach_type {
* @mode: operation mode (enum bpf_adj_room_mode)
* @flags: reserved for future use
* Return: 0 on success or negative error code
+ *
+ * int bpf_sk_redirect_map(map, key, flags)
+ * Redirect skb to a sock in map using key as a lookup key for the
+ * sock in map.
+ * @map: pointer to sockmap
+ * @key: key to lookup sock in map
+ * @flags: reserved for future use
+ * Return: SK_REDIRECT
+ *
+ * int bpf_sock_map_update(skops, map, key, flags, map_flags)
+ * @skops: pointer to bpf_sock_ops
+ * @map: pointer to sockmap to update
+ * @key: key to insert/update sock in map
+ * @flags: same flags as map update elem
+ * @map_flags: sock map specific flags
+ * bit 1: Enable strparser
+ * other bits: reserved
*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
@@ -610,7 +633,9 @@ enum bpf_attach_type {
FN(set_hash), \
FN(setsockopt), \
FN(skb_adjust_room), \
- FN(redirect_map),
+ FN(redirect_map), \
+ FN(sk_redirect_map), \
+ FN(sock_map_update), \
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call
@@ -747,6 +772,12 @@ struct xdp_md {
__u32 data_end;
};
+enum sk_action {
+ SK_ABORTED = 0,
+ SK_DROP,
+ SK_REDIRECT,
+};
+
#define BPF_TAG_SIZE 8
struct bpf_prog_info {
diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
index 2f0bcda..aa24287 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
ifeq ($(CONFIG_NET),y)
-obj-$(CONFIG_BPF_SYSCALL) += devmap.o
+obj-$(CONFIG_BPF_SYSCALL) += devmap.o sockmap.o
endif
ifeq ($(CONFIG_PERF_EVENTS),y)
obj-$(CONFIG_BPF_SYSCALL) += stackmap.o
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c
new file mode 100644
index 0000000..792f0ad
--- /dev/null
+++ b/kernel/bpf/sockmap.c
@@ -0,0 +1,792 @@
+/* Copyright (c) 2017 Covalent IO, Inc. http://covalent.io
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/* A BPF sock_map is used to store sock objects. This is primarly used
+ * for doing socket redirect with BPF helper routines.
+ *
+ * A sock map may have two BPF programs attached to it, a program used
+ * to parse packets and a program to provide a verdict and redirect
+ * decision on the packet. If no BPF parse program is provided it is
+ * assumed that every skb is a "message" (skb->len). Otherwise the
+ * parse program is attached to strparser and used to build messages
+ * that may span multiple skbs. The verdict program will either select
+ * a socket to send/receive the skb on or provide the drop code indicating
+ * the skb should be dropped. More actions may be added later as needed.
+ * The default program will drop packets.
+ *
+ * For reference this program is similar to devmap used in XDP context
+ * reviewing these together may be useful. For an example please review
+ * ./samples/bpf/sockmap/.
+ */
+#include <linux/bpf.h>
+#include <net/sock.h>
+#include <linux/filter.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/kernel.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/workqueue.h>
+#include <linux/list.h>
+#include <net/strparser.h>
+
+struct bpf_stab {
+ struct bpf_map map;
+ struct sock **sock_map;
+ struct bpf_prog *bpf_parse;
+ struct bpf_prog *bpf_verdict;
+ refcount_t refcnt;
+};
+
+enum smap_psock_state {
+ SMAP_TX_RUNNING,
+};
+
+struct smap_psock {
+ struct rcu_head rcu;
+
+ /* datapath variables */
+ struct sk_buff_head rxqueue;
+ bool strp_enabled;
+
+ /* datapath error path cache across tx work invocations */
+ int save_rem;
+ int save_off;
+ struct sk_buff *save_skb;
+
+ struct strparser strp;
+ struct bpf_prog *bpf_parse;
+ struct bpf_prog *bpf_verdict;
+ struct bpf_stab *stab;
+
+ /* Back reference used when sock callback trigger sockmap operations */
+ int key;
+ struct sock *sock;
+ unsigned long state;
+
+ struct work_struct tx_work;
+ struct work_struct gc_work;
+
+ void (*save_data_ready)(struct sock *sk);
+ void (*save_write_space)(struct sock *sk);
+ void (*save_state_change)(struct sock *sk);
+};
+
+static inline struct smap_psock *smap_psock_sk(const struct sock *sk)
+{
+ return (struct smap_psock *)rcu_dereference_sk_user_data(sk);
+}
+
+static int smap_verdict_func(struct smap_psock *psock, struct sk_buff *skb)
+{
+ struct bpf_prog *prog = READ_ONCE(psock->bpf_verdict);
+ int rc;
+
+ if (unlikely(!prog))
+ return SK_DROP;
+
+ skb_orphan(skb);
+ skb->sk = psock->sock;
+ bpf_compute_data_end(skb);
+ rc = (*prog->bpf_func)(skb, prog->insnsi);
+ skb->sk = NULL;
+
+ return rc;
+}
+
+static void smap_do_verdict(struct smap_psock *psock, struct sk_buff *skb)
+{
+ struct sock *sock;
+ int rc;
+
+ /* Because we use per cpu values to feed input from sock redirect
+ * in BPF program to do_sk_redirect_map() call we need to ensure we
+ * are not preempted. RCU read lock is not sufficient in this case
+ * with CONFIG_PREEMPT_RCU enabled so we must be explicit here.
+ */
+ preempt_disable();
+ rc = smap_verdict_func(psock, skb);
+ switch (rc) {
+ case SK_REDIRECT:
+ sock = do_sk_redirect_map();
+ preempt_enable();
+ if (likely(sock)) {
+ struct smap_psock *peer = smap_psock_sk(sock);
+
+ if (likely(peer &&
+ test_bit(SMAP_TX_RUNNING, &peer->state) &&
+ sk_stream_memory_free(peer->sock))) {
+ peer->sock->sk_wmem_queued += skb->truesize;
+ sk_mem_charge(peer->sock, skb->truesize);
+ skb_queue_tail(&peer->rxqueue, skb);
+ schedule_work(&peer->tx_work);
+ break;
+ }
+ }
+ /* Fall through and free skb otherwise */
+ case SK_DROP:
+ default:
+ preempt_enable();
+ kfree_skb(skb);
+ }
+}
+
+static void smap_report_sk_error(struct smap_psock *psock, int err)
+{
+ struct sock *sk = psock->sock;
+
+ sk->sk_err = err;
+ sk->sk_error_report(sk);
+}
+
+static void smap_release_sock(struct sock *sock);
+
+/* Called with lock_sock(sk) held */
+static void smap_state_change(struct sock *sk)
+{
+ struct smap_psock *psock;
+ struct sock *osk;
+
+ rcu_read_lock();
+
+ /* Allowing transitions into an established syn_recv states allows
+ * for early binding sockets to a smap object before the connection
+ * is established.
+ */
+ switch (sk->sk_state) {
+ case TCP_SYN_RECV:
+ case TCP_ESTABLISHED:
+ break;
+ case TCP_CLOSE_WAIT:
+ case TCP_CLOSING:
+ case TCP_LAST_ACK:
+ case TCP_FIN_WAIT1:
+ case TCP_FIN_WAIT2:
+ case TCP_LISTEN:
+ break;
+ case TCP_CLOSE:
+ /* Only release if the map entry is in fact the sock in
+ * question. There is a case where the operator deletes
+ * the sock from the map, but the TCP sock is closed before
+ * the psock is detached. Use cmpxchg to verify correct
+ * sock is removed.
+ */
+ psock = smap_psock_sk(sk);
+ if (unlikely(!psock))
+ break;
+ osk = cmpxchg(&psock->stab->sock_map[psock->key], sk, NULL);
+ if (osk == sk)
+ smap_release_sock(sk);
+ break;
+ default:
+ smap_report_sk_error(psock, EPIPE);
+ break;
+ }
+ rcu_read_unlock();
+}
+
+static void smap_read_sock_strparser(struct strparser *strp,
+ struct sk_buff *skb)
+{
+ struct smap_psock *psock;
+
+ rcu_read_lock();
+ psock = container_of(strp, struct smap_psock, strp);
+ smap_do_verdict(psock, skb);
+ rcu_read_unlock();
+}
+
+/* Called with lock held on socket */
+static void smap_data_ready(struct sock *sk)
+{
+ struct smap_psock *psock;
+
+ write_lock_bh(&sk->sk_callback_lock);
+ psock = smap_psock_sk(sk);
+ if (likely(psock))
+ strp_data_ready(&psock->strp);
+ write_unlock_bh(&sk->sk_callback_lock);
+}
+
+static void smap_tx_work(struct work_struct *w)
+{
+ struct smap_psock *psock;
+ struct sk_buff *skb;
+ int rem, off, n;
+
+ psock = container_of(w, struct smap_psock, tx_work);
+
+ /* lock sock to avoid losing sk_socket at some point during loop */
+ lock_sock(psock->sock);
+ if (psock->save_skb) {
+ skb = psock->save_skb;
+ rem = psock->save_rem;
+ off = psock->save_off;
+ psock->save_skb = NULL;
+ goto start;
+ }
+
+ while ((skb = skb_dequeue(&psock->rxqueue))) {
+ rem = skb->len;
+ off = 0;
+start:
+ do {
+ if (likely(psock->sock->sk_socket))
+ n = skb_send_sock_locked(psock->sock,
+ skb, off, rem);
+ else
+ n = -EINVAL;
+ if (n <= 0) {
+ if (n == -EAGAIN) {
+ /* Retry when space is available */
+ psock->save_skb = skb;
+ psock->save_rem = rem;
+ psock->save_off = off;
+ goto out;
+ }
+ /* Hard errors break pipe and stop xmit */
+ smap_report_sk_error(psock, n ? -n : EPIPE);
+ clear_bit(SMAP_TX_RUNNING, &psock->state);
+ sk_mem_uncharge(psock->sock, skb->truesize);
+ psock->sock->sk_wmem_queued -= skb->truesize;
+ kfree_skb(skb);
+ goto out;
+ }
+ rem -= n;
+ off += n;
+ } while (rem);
+ sk_mem_uncharge(psock->sock, skb->truesize);
+ psock->sock->sk_wmem_queued -= skb->truesize;
+ kfree_skb(skb);
+ }
+out:
+ release_sock(psock->sock);
+}
+
+static void smap_write_space(struct sock *sk)
+{
+ struct smap_psock *psock;
+
+ rcu_read_lock();
+ psock = smap_psock_sk(sk);
+ if (likely(psock && test_bit(SMAP_TX_RUNNING, &psock->state)))
+ schedule_work(&psock->tx_work);
+ rcu_read_unlock();
+}
+
+static void smap_stop_sock(struct smap_psock *psock, struct sock *sk)
+{
+ write_lock_bh(&sk->sk_callback_lock);
+ if (!psock->strp_enabled)
+ goto out;
+ sk->sk_data_ready = psock->save_data_ready;
+ sk->sk_write_space = psock->save_write_space;
+ sk->sk_state_change = psock->save_state_change;
+ psock->save_data_ready = NULL;
+ psock->save_write_space = NULL;
+ psock->save_state_change = NULL;
+ strp_stop(&psock->strp);
+ psock->strp_enabled = false;
+out:
+ write_unlock_bh(&sk->sk_callback_lock);
+}
+
+static void smap_destroy_psock(struct rcu_head *rcu)
+{
+ struct smap_psock *psock = container_of(rcu,
+ struct smap_psock, rcu);
+
+ /* Now that a grace period has passed there is no longer
+ * any reference to this sock in the sockmap so we can
+ * destroy the psock, strparser, and bpf programs. But,
+ * because we use workqueue sync operations we can not
+ * do it in rcu context
+ */
+ schedule_work(&psock->gc_work);
+}
+
+static void smap_release_sock(struct sock *sock)
+{
+ struct smap_psock *psock = smap_psock_sk(sock);
+
+ smap_stop_sock(psock, sock);
+ clear_bit(SMAP_TX_RUNNING, &psock->state);
+ rcu_assign_sk_user_data(sock, NULL);
+ call_rcu_sched(&psock->rcu, smap_destroy_psock);
+}
+
+static int smap_parse_func_strparser(struct strparser *strp,
+ struct sk_buff *skb)
+{
+ struct smap_psock *psock;
+ struct bpf_prog *prog;
+ int rc;
+
+ rcu_read_lock();
+ psock = container_of(strp, struct smap_psock, strp);
+ prog = READ_ONCE(psock->bpf_parse);
+
+ if (unlikely(!prog)) {
+ rcu_read_unlock();
+ return skb->len;
+ }
+
+ /* Attach socket for bpf program to use if needed we can do this
+ * because strparser clones the skb before handing it to a upper
+ * layer, meaning skb_orphan has been called. We NULL sk on the
+ * way out to ensure we don't trigger a BUG_ON in skb/sk operations
+ * later and because we are not charging the memory of this skb to
+ * any socket yet.
+ */
+ skb->sk = psock->sock;
+ bpf_compute_data_end(skb);
+ rc = (*prog->bpf_func)(skb, prog->insnsi);
+ skb->sk = NULL;
+ rcu_read_unlock();
+ return rc;
+}
+
+
+static int smap_read_sock_done(struct strparser *strp, int err)
+{
+ return err;
+}
+
+static int smap_init_sock(struct smap_psock *psock,
+ struct sock *sk)
+{
+ struct strp_callbacks cb;
+
+ memset(&cb, 0, sizeof(cb));
+ cb.rcv_msg = smap_read_sock_strparser;
+ cb.parse_msg = smap_parse_func_strparser;
+ cb.read_sock_done = smap_read_sock_done;
+ return strp_init(&psock->strp, sk, &cb);
+}
+
+static void smap_init_progs(struct smap_psock *psock,
+ struct bpf_stab *stab,
+ struct bpf_prog *verdict,
+ struct bpf_prog *parse)
+{
+ struct bpf_prog *orig_parse, *orig_verdict;
+
+ orig_parse = xchg(&psock->bpf_parse, parse);
+ orig_verdict = xchg(&psock->bpf_verdict, verdict);
+
+ if (orig_verdict)
+ bpf_prog_put(orig_verdict);
+ if (orig_parse)
+ bpf_prog_put(orig_parse);
+}
+
+static void smap_start_sock(struct smap_psock *psock, struct sock *sk)
+{
+ if (sk->sk_data_ready == smap_data_ready)
+ return;
+ psock->save_data_ready = sk->sk_data_ready;
+ psock->save_write_space = sk->sk_write_space;
+ psock->save_state_change = sk->sk_state_change;
+ sk->sk_data_ready = smap_data_ready;
+ sk->sk_write_space = smap_write_space;
+ sk->sk_state_change = smap_state_change;
+ psock->strp_enabled = true;
+}
+
+static void sock_map_remove_complete(struct bpf_stab *stab)
+{
+ bpf_map_area_free(stab->sock_map);
+ kfree(stab);
+}
+
+static void smap_gc_work(struct work_struct *w)
+{
+ struct smap_psock *psock;
+
+ psock = container_of(w, struct smap_psock, gc_work);
+
+ /* no callback lock needed because we already detached sockmap ops */
+ if (psock->strp_enabled)
+ strp_done(&psock->strp);
+
+ cancel_work_sync(&psock->tx_work);
+ __skb_queue_purge(&psock->rxqueue);
+
+ /* At this point all strparser and xmit work must be complete */
+ if (psock->bpf_parse)
+ bpf_prog_put(psock->bpf_parse);
+ if (psock->bpf_verdict)
+ bpf_prog_put(psock->bpf_verdict);
+
+ if (refcount_dec_and_test(&psock->stab->refcnt))
+ sock_map_remove_complete(psock->stab);
+
+ sock_put(psock->sock);
+ kfree(psock);
+}
+
+static struct smap_psock *smap_init_psock(struct sock *sock,
+ struct bpf_stab *stab)
+{
+ struct smap_psock *psock;
+
+ psock = kzalloc(sizeof(struct smap_psock), GFP_ATOMIC | __GFP_NOWARN);
+ if (!psock)
+ return ERR_PTR(-ENOMEM);
+
+ psock->sock = sock;
+ skb_queue_head_init(&psock->rxqueue);
+ INIT_WORK(&psock->tx_work, smap_tx_work);
+ INIT_WORK(&psock->gc_work, smap_gc_work);
+
+ rcu_assign_sk_user_data(sock, psock);
+ sock_hold(sock);
+ return psock;
+}
+
+static struct bpf_map *sock_map_alloc(union bpf_attr *attr)
+{
+ struct bpf_stab *stab;
+ int err = -EINVAL;
+ u64 cost;
+
+ /* check sanity of attributes */
+ if (attr->max_entries == 0 || attr->key_size != 4 ||
+ attr->value_size != 4 || attr->map_flags)
+ return ERR_PTR(-EINVAL);
+
+ if (attr->value_size > KMALLOC_MAX_SIZE)
+ return ERR_PTR(-E2BIG);
+
+ stab = kzalloc(sizeof(*stab), GFP_USER);
+ if (!stab)
+ return ERR_PTR(-ENOMEM);
+
+ /* mandatory map attributes */
+ stab->map.map_type = attr->map_type;
+ stab->map.key_size = attr->key_size;
+ stab->map.value_size = attr->value_size;
+ stab->map.max_entries = attr->max_entries;
+ stab->map.map_flags = attr->map_flags;
+
+ /* make sure page count doesn't overflow */
+ cost = (u64) stab->map.max_entries * sizeof(struct sock *);
+ if (cost >= U32_MAX - PAGE_SIZE)
+ goto free_stab;
+
+ stab->map.pages = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT;
+
+ /* if map size is larger than memlock limit, reject it early */
+ err = bpf_map_precharge_memlock(stab->map.pages);
+ if (err)
+ goto free_stab;
+
+ stab->sock_map = bpf_map_area_alloc(stab->map.max_entries *
+ sizeof(struct sock *));
+ if (!stab->sock_map)
+ goto free_stab;
+
+ refcount_set(&stab->refcnt, 1);
+ return &stab->map;
+free_stab:
+ kfree(stab);
+ return ERR_PTR(err);
+}
+
+static void sock_map_free(struct bpf_map *map)
+{
+ struct bpf_stab *stab = container_of(map, struct bpf_stab, map);
+ int i;
+
+ synchronize_rcu();
+
+ /* At this point no update, lookup or delete operations can happen.
+ * However, be aware we can still get a socket state event updates,
+ * and data ready callabacks that reference the psock from sk_user_data
+ * Also psock worker threads are still in-flight. So smap_release_sock
+ * will only free the psock after cancel_sync on the worker threads
+ * and a grace period expire to ensure psock is really safe to remove.
+ */
+ rcu_read_lock();
+ for (i = 0; i < stab->map.max_entries; i++) {
+ struct sock *sock;
+
+ sock = xchg(&stab->sock_map[i], NULL);
+ if (!sock)
+ continue;
+
+ smap_release_sock(sock);
+ }
+ rcu_read_unlock();
+
+ if (stab->bpf_verdict)
+ bpf_prog_put(stab->bpf_verdict);
+ if (stab->bpf_parse)
+ bpf_prog_put(stab->bpf_parse);
+
+ if (refcount_dec_and_test(&stab->refcnt))
+ sock_map_remove_complete(stab);
+}
+
+static int sock_map_get_next_key(struct bpf_map *map, void *key, void *next_key)
+{
+ struct bpf_stab *stab = container_of(map, struct bpf_stab, map);
+ u32 i = key ? *(u32 *)key : U32_MAX;
+ u32 *next = (u32 *)next_key;
+
+ if (i >= stab->map.max_entries) {
+ *next = 0;
+ return 0;
+ }
+
+ if (i == stab->map.max_entries - 1)
+ return -ENOENT;
+
+ *next = i + 1;
+ return 0;
+}
+
+struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key)
+{
+ struct bpf_stab *stab = container_of(map, struct bpf_stab, map);
+
+ if (key >= map->max_entries)
+ return NULL;
+
+ return READ_ONCE(stab->sock_map[key]);
+}
+
+static int sock_map_delete_elem(struct bpf_map *map, void *key)
+{
+ struct bpf_stab *stab = container_of(map, struct bpf_stab, map);
+ int k = *(u32 *)key;
+ struct sock *sock;
+
+ if (k >= map->max_entries)
+ return -EINVAL;
+
+ sock = xchg(&stab->sock_map[k], NULL);
+ if (!sock)
+ return -EINVAL;
+
+ smap_release_sock(sock);
+ return 0;
+}
+
+/* Locking notes: Concurrent updates, deletes, and lookups are allowed and are
+ * done inside rcu critical sections. This ensures on updates that the psock
+ * will not be released via smap_release_sock() until concurrent updates/deletes
+ * complete. All operations operate on sock_map using cmpxchg and xchg
+ * operations to ensure we do not get stale references. Any reads into the
+ * map must be done with READ_ONCE() because of this.
+ *
+ * A psock is destroyed via call_rcu and after any worker threads are cancelled
+ * and syncd so we are certain all references from the update/lookup/delete
+ * operations as well as references in the data path are no longer in use.
+ *
+ * A psock object holds a refcnt on the sockmap it is attached to and this is
+ * not decremented until after a RCU grace period and garbage collection occurs.
+ * This ensures the map is not free'd until psocks linked to it are removed. The
+ * map link is used when the independent sock events trigger map deletion.
+ *
+ * Psocks may only participate in one sockmap at a time. Users that try to
+ * join a single sock to multiple maps will get an error.
+ *
+ * Last, but not least, it is possible the socket is closed while running
+ * an update on an existing psock. This will release the psock, but again
+ * not until the update has completed due to rcu grace period rules.
+ */
+static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
+ struct bpf_map *map,
+ void *key, u64 flags, u64 map_flags)
+{
+ struct bpf_stab *stab = container_of(map, struct bpf_stab, map);
+ struct bpf_prog *verdict, *parse;
+ struct smap_psock *psock = NULL;
+ struct sock *old_sock, *sock;
+ u32 i = *(u32 *)key;
+ bool update = false;
+ int err = 0;
+
+ if (unlikely(flags > BPF_EXIST))
+ return -EINVAL;
+
+ if (unlikely(i >= stab->map.max_entries))
+ return -E2BIG;
+
+ if (unlikely(map_flags > BPF_SOCKMAP_STRPARSER))
+ return -EINVAL;
+
+ verdict = parse = NULL;
+ sock = READ_ONCE(stab->sock_map[i]);
+
+ if (flags == BPF_EXIST || flags == BPF_ANY) {
+ if (!sock && flags == BPF_EXIST) {
+ return -ENOENT;
+ } else if (sock && sock != skops->sk) {
+ return -EINVAL;
+ } else if (sock) {
+ psock = smap_psock_sk(sock);
+ if (unlikely(!psock))
+ return -EBUSY;
+ update = true;
+ }
+ } else if (sock && BPF_NOEXIST) {
+ return -EEXIST;
+ }
+
+ /* reserve BPF programs early so can abort easily on failures */
+ if (map_flags & BPF_SOCKMAP_STRPARSER) {
+ verdict = READ_ONCE(stab->bpf_verdict);
+ parse = READ_ONCE(stab->bpf_parse);
+
+ if (!verdict || !parse)
+ return -ENOENT;
+
+ /* bpf prog refcnt may be zero if a concurrent attach operation
+ * removes the program after the above READ_ONCE() but before
+ * we increment the refcnt. If this is the case abort with an
+ * error.
+ */
+ verdict = bpf_prog_inc_not_zero(stab->bpf_verdict);
+ if (IS_ERR(verdict))
+ return PTR_ERR(verdict);
+
+ parse = bpf_prog_inc_not_zero(stab->bpf_parse);
+ if (IS_ERR(parse)) {
+ bpf_prog_put(verdict);
+ return PTR_ERR(parse);
+ }
+ }
+
+ if (!psock) {
+ sock = skops->sk;
+ if (rcu_dereference_sk_user_data(sock))
+ return -EEXIST;
+ psock = smap_init_psock(sock, stab);
+ if (IS_ERR(psock)) {
+ if (verdict)
+ bpf_prog_put(verdict);
+ if (parse)
+ bpf_prog_put(parse);
+ return PTR_ERR(psock);
+ }
+ psock->key = i;
+ psock->stab = stab;
+ refcount_inc(&stab->refcnt);
+ set_bit(SMAP_TX_RUNNING, &psock->state);
+ }
+
+ if (map_flags & BPF_SOCKMAP_STRPARSER) {
+ write_lock_bh(&sock->sk_callback_lock);
+ if (psock->strp_enabled)
+ goto start_done;
+ err = smap_init_sock(psock, sock);
+ if (err)
+ goto out;
+ smap_init_progs(psock, stab, verdict, parse);
+ smap_start_sock(psock, sock);
+start_done:
+ write_unlock_bh(&sock->sk_callback_lock);
+ } else if (update) {
+ smap_stop_sock(psock, sock);
+ }
+
+ if (!update) {
+ old_sock = xchg(&stab->sock_map[i], skops->sk);
+ if (old_sock)
+ smap_release_sock(old_sock);
+ }
+
+ return 0;
+out:
+ write_unlock_bh(&sock->sk_callback_lock);
+ if (!update)
+ smap_release_sock(sock);
+ return err;
+}
+
+static int sock_map_attach_prog(struct bpf_map *map,
+ struct bpf_prog *parse,
+ struct bpf_prog *verdict)
+{
+ struct bpf_stab *stab = container_of(map, struct bpf_stab, map);
+ struct bpf_prog *_parse, *_verdict;
+
+ _parse = xchg(&stab->bpf_parse, parse);
+ _verdict = xchg(&stab->bpf_verdict, verdict);
+
+ if (_parse)
+ bpf_prog_put(_parse);
+ if (_verdict)
+ bpf_prog_put(_verdict);
+
+ return 0;
+}
+
+static void *sock_map_lookup(struct bpf_map *map, void *key)
+{
+ return NULL;
+}
+
+static int sock_map_update_elem(struct bpf_map *map,
+ void *key, void *value, u64 flags)
+{
+ struct bpf_sock_ops_kern skops;
+ u32 fd = *(u32 *)value;
+ struct socket *socket;
+ int err;
+
+ socket = sockfd_lookup(fd, &err);
+ if (!socket)
+ return err;
+
+ skops.sk = socket->sk;
+ if (!skops.sk) {
+ fput(socket->file);
+ return -EINVAL;
+ }
+
+ err = sock_map_ctx_update_elem(&skops, map, key,
+ flags, BPF_SOCKMAP_STRPARSER);
+ fput(socket->file);
+ return err;
+}
+
+const struct bpf_map_ops sock_map_ops = {
+ .map_alloc = sock_map_alloc,
+ .map_free = sock_map_free,
+ .map_lookup_elem = sock_map_lookup,
+ .map_get_next_key = sock_map_get_next_key,
+ .map_update_elem = sock_map_update_elem,
+ .map_delete_elem = sock_map_delete_elem,
+ .map_attach = sock_map_attach_prog,
+};
+
+BPF_CALL_5(bpf_sock_map_update, struct bpf_sock_ops_kern *, bpf_sock,
+ struct bpf_map *, map, void *, key, u64, flags, u64, map_flags)
+{
+ WARN_ON_ONCE(!rcu_read_lock_held());
+ return sock_map_ctx_update_elem(bpf_sock, map, key, flags, map_flags);
+}
+
+const struct bpf_func_proto bpf_sock_map_update_proto = {
+ .func = bpf_sock_map_update,
+ .gpl_only = false,
+ .pkt_access = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_PTR_TO_CTX,
+ .arg2_type = ARG_CONST_MAP_PTR,
+ .arg3_type = ARG_PTR_TO_MAP_KEY,
+ .arg4_type = ARG_ANYTHING,
+ .arg5_type = ARG_ANYTHING,
+};
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 17e29f5..d2f2bdf 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -1087,7 +1087,50 @@ static int bpf_obj_get(const union bpf_attr *attr)
#ifdef CONFIG_CGROUP_BPF
-#define BPF_PROG_ATTACH_LAST_FIELD attach_flags
+#define BPF_PROG_ATTACH_LAST_FIELD attach_bpf_fd2
+
+static int sockmap_get_from_fd(const union bpf_attr *attr, int ptype)
+{
+ struct bpf_prog *prog1, *prog2;
+ int ufd = attr->target_fd;
+ struct bpf_map *map;
+ struct fd f;
+ int err;
+
+ f = fdget(ufd);
+ map = __bpf_map_get(f);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ if (!map->ops->map_attach) {
+ fdput(f);
+ return -EOPNOTSUPP;
+ }
+
+ prog1 = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
+ if (IS_ERR(prog1)) {
+ fdput(f);
+ return PTR_ERR(prog1);
+ }
+
+ prog2 = bpf_prog_get_type(attr->attach_bpf_fd2, ptype);
+ if (IS_ERR(prog2)) {
+ fdput(f);
+ bpf_prog_put(prog1);
+ return PTR_ERR(prog2);
+ }
+
+ err = map->ops->map_attach(map, prog1, prog2);
+ if (err) {
+ fdput(f);
+ bpf_prog_put(prog1);
+ bpf_prog_put(prog2);
+ return PTR_ERR(map);
+ }
+
+ fdput(f);
+ return err;
+}
static int bpf_prog_attach(const union bpf_attr *attr)
{
@@ -1116,10 +1159,16 @@ static int bpf_prog_attach(const union bpf_attr *attr)
case BPF_CGROUP_SOCK_OPS:
ptype = BPF_PROG_TYPE_SOCK_OPS;
break;
+ case BPF_CGROUP_SMAP_INGRESS:
+ ptype = BPF_PROG_TYPE_SK_SKB;
+ break;
default:
return -EINVAL;
}
+ if (attr->attach_type == BPF_CGROUP_SMAP_INGRESS)
+ return sockmap_get_from_fd(attr, ptype);
+
prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
if (IS_ERR(prog))
return PTR_ERR(prog);
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index ecc590e..a439ad5 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -1486,6 +1486,12 @@ static int check_map_func_compatibility(struct bpf_map *map, int func_id)
case BPF_MAP_TYPE_HASH_OF_MAPS:
if (func_id != BPF_FUNC_map_lookup_elem)
goto error;
+ case BPF_MAP_TYPE_SOCKMAP:
+ if (func_id != BPF_FUNC_sk_redirect_map &&
+ func_id != BPF_FUNC_sock_map_update &&
+ func_id != BPF_FUNC_map_delete_elem)
+ goto error;
+ break;
default:
break;
}
@@ -1514,6 +1520,14 @@ static int check_map_func_compatibility(struct bpf_map *map, int func_id)
if (map->map_type != BPF_MAP_TYPE_DEVMAP)
goto error;
break;
+ case BPF_FUNC_sk_redirect_map:
+ if (map->map_type != BPF_MAP_TYPE_SOCKMAP)
+ goto error;
+ break;
+ case BPF_FUNC_sock_map_update:
+ if (map->map_type != BPF_MAP_TYPE_SOCKMAP)
+ goto error;
+ break;
default:
break;
}
diff --git a/net/core/filter.c b/net/core/filter.c
index c1108bf..934b92f 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -1858,6 +1858,45 @@ int skb_do_redirect(struct sk_buff *skb)
.arg3_type = ARG_ANYTHING,
};
+BPF_CALL_3(bpf_sk_redirect_map, struct bpf_map *, map, u32, key, u64, flags)
+{
+ struct redirect_info *ri = this_cpu_ptr(&redirect_info);
+
+ if (unlikely(flags))
+ return SK_ABORTED;
+
+ ri->ifindex = key;
+ ri->flags = flags;
+ ri->map = map;
+
+ return SK_REDIRECT;
+}
+
+struct sock *do_sk_redirect_map(void)
+{
+ struct redirect_info *ri = this_cpu_ptr(&redirect_info);
+ struct sock *sk = NULL;
+
+ if (ri->map) {
+ sk = __sock_map_lookup_elem(ri->map, ri->ifindex);
+
+ ri->ifindex = 0;
+ ri->map = NULL;
+ /* we do not clear flags for future lookup */
+ }
+
+ return sk;
+}
+
+static const struct bpf_func_proto bpf_sk_redirect_map_proto = {
+ .func = bpf_sk_redirect_map,
+ .gpl_only = false,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_CONST_MAP_PTR,
+ .arg2_type = ARG_ANYTHING,
+ .arg3_type = ARG_ANYTHING,
+};
+
BPF_CALL_1(bpf_get_cgroup_classid, const struct sk_buff *, skb)
{
return task_get_classid(skb);
@@ -3229,6 +3268,8 @@ static unsigned long bpf_xdp_copy(void *dst_buff, const void *src_buff,
switch (func_id) {
case BPF_FUNC_setsockopt:
return &bpf_setsockopt_proto;
+ case BPF_FUNC_sock_map_update:
+ return &bpf_sock_map_update_proto;
default:
return bpf_base_func_proto(func_id);
}
@@ -3243,6 +3284,8 @@ static const struct bpf_func_proto *sk_skb_func_proto(enum bpf_func_id func_id)
return &bpf_get_socket_cookie_proto;
case BPF_FUNC_get_socket_uid:
return &bpf_get_socket_uid_proto;
+ case BPF_FUNC_sk_redirect_map:
+ return &bpf_sk_redirect_map_proto;
default:
return bpf_base_func_proto(func_id);
}
^ 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