Skip to content

Commit d39d714

Browse files
congwangdavem330
authored andcommitted
idr: introduce idr_for_each_entry_continue_ul()
Similarly, other callers of idr_get_next_ul() suffer the same overflow bug as they don't handle it properly either. Introduce idr_for_each_entry_continue_ul() to help these callers iterate from a given ID. cls_flower needs more care here because it still has overflow when does arg->cookie++, we have to fold its nested loops into one and remove the arg->cookie++. Fixes: 01683a1 ("net: sched: refactor flower walk to iterate over idr") Fixes: 12d6066 ("net/mlx5: Add flow counters idr") Reported-by: Li Shuang <[email protected]> Cc: Davide Caratti <[email protected]> Cc: Vlad Buslov <[email protected]> Cc: Chris Mi <[email protected]> Cc: Matthew Wilcox <[email protected]> Signed-off-by: Cong Wang <[email protected]> Tested-by: Davide Caratti <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e33d2b7 commit d39d714

File tree

3 files changed

+27
-24
lines changed

3 files changed

+27
-24
lines changed

drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,15 @@ static struct list_head *mlx5_fc_counters_lookup_next(struct mlx5_core_dev *dev,
102102
struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
103103
unsigned long next_id = (unsigned long)id + 1;
104104
struct mlx5_fc *counter;
105+
unsigned long tmp;
105106

106107
rcu_read_lock();
107108
/* skip counters that are in idr, but not yet in counters list */
108-
while ((counter = idr_get_next_ul(&fc_stats->counters_idr,
109-
&next_id)) != NULL &&
110-
list_empty(&counter->list))
111-
next_id++;
109+
idr_for_each_entry_continue_ul(&fc_stats->counters_idr,
110+
counter, tmp, next_id) {
111+
if (!list_empty(&counter->list))
112+
break;
113+
}
112114
rcu_read_unlock();
113115

114116
return counter ? &counter->list : &fc_stats->counters;

include/linux/idr.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,20 @@ static inline void idr_preload_end(void)
216216
entry; \
217217
++id, (entry) = idr_get_next((idr), &(id)))
218218

219+
/**
220+
* idr_for_each_entry_continue_ul() - Continue iteration over an IDR's elements of a given type
221+
* @idr: IDR handle.
222+
* @entry: The type * to use as a cursor.
223+
* @tmp: A temporary placeholder for ID.
224+
* @id: Entry ID.
225+
*
226+
* Continue to iterate over entries, continuing after the current position.
227+
*/
228+
#define idr_for_each_entry_continue_ul(idr, entry, tmp, id) \
229+
for (tmp = id; \
230+
tmp <= id && ((entry) = idr_get_next_ul(idr, &(id))) != NULL; \
231+
tmp = id, ++id)
232+
219233
/*
220234
* IDA - ID Allocator, use when translation from id to pointer isn't necessary.
221235
*/

net/sched/cls_flower.c

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -524,24 +524,6 @@ static struct cls_fl_filter *__fl_get(struct cls_fl_head *head, u32 handle)
524524
return f;
525525
}
526526

527-
static struct cls_fl_filter *fl_get_next_filter(struct tcf_proto *tp,
528-
unsigned long *handle)
529-
{
530-
struct cls_fl_head *head = fl_head_dereference(tp);
531-
struct cls_fl_filter *f;
532-
533-
rcu_read_lock();
534-
while ((f = idr_get_next_ul(&head->handle_idr, handle))) {
535-
/* don't return filters that are being deleted */
536-
if (refcount_inc_not_zero(&f->refcnt))
537-
break;
538-
++(*handle);
539-
}
540-
rcu_read_unlock();
541-
542-
return f;
543-
}
544-
545527
static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
546528
bool *last, bool rtnl_held,
547529
struct netlink_ext_ack *extack)
@@ -1691,20 +1673,25 @@ static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
16911673
static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg,
16921674
bool rtnl_held)
16931675
{
1676+
struct cls_fl_head *head = fl_head_dereference(tp);
1677+
unsigned long id = arg->cookie, tmp;
16941678
struct cls_fl_filter *f;
16951679

16961680
arg->count = arg->skip;
16971681

1698-
while ((f = fl_get_next_filter(tp, &arg->cookie)) != NULL) {
1682+
idr_for_each_entry_continue_ul(&head->handle_idr, f, tmp, id) {
1683+
/* don't return filters that are being deleted */
1684+
if (!refcount_inc_not_zero(&f->refcnt))
1685+
continue;
16991686
if (arg->fn(tp, f, arg) < 0) {
17001687
__fl_put(f);
17011688
arg->stop = 1;
17021689
break;
17031690
}
17041691
__fl_put(f);
1705-
arg->cookie++;
17061692
arg->count++;
17071693
}
1694+
arg->cookie = id;
17081695
}
17091696

17101697
static struct cls_fl_filter *

0 commit comments

Comments
 (0)