}
static void mptcp_pm_flush_addrs_and_subflows(struct mptcp_sock *msk,
- struct list_head *rm_list)
+ struct list_head *rm_list,
+ struct mptcp_pm_addr_entry *entry)
{
- struct mptcp_rm_list alist = { .nr = 0 }, slist = { .nr = 0 };
- struct mptcp_pm_addr_entry *entry;
+ struct mptcp_rm_list alist, slist;
+ bool more;
+
+again:
+ alist.nr = 0;
+ slist.nr = 0;
+ more = false;
- list_for_each_entry(entry, rm_list, list) {
- if (slist.nr < MPTCP_RM_IDS_MAX &&
- mptcp_lookup_subflow_by_saddr(&msk->conn_list, &entry->addr))
+ entry = list_prepare_entry(entry, rm_list, list);
+ list_for_each_entry_continue(entry, rm_list, list) {
+ if (mptcp_lookup_subflow_by_saddr(&msk->conn_list, &entry->addr))
slist.ids[slist.nr++] = mptcp_endp_get_local_id(msk, &entry->addr);
- if (alist.nr < MPTCP_RM_IDS_MAX &&
- mptcp_remove_anno_list_by_saddr(msk, &entry->addr))
+ if (mptcp_remove_anno_list_by_saddr(msk, &entry->addr))
alist.ids[alist.nr++] = mptcp_endp_get_local_id(msk, &entry->addr);
+
+ if (slist.nr == MPTCP_RM_IDS_MAX ||
+ alist.nr == MPTCP_RM_IDS_MAX) {
+ more = !list_is_last(&entry->list, rm_list);
+ break;
+ }
}
spin_lock_bh(&msk->pm.lock);
if (slist.nr)
mptcp_pm_rm_subflow(msk, &slist);
/* Reset counters: maybe some subflows have been removed before */
- bitmap_fill(msk->pm.id_avail_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);
- msk->pm.local_addr_used = 0;
+ if (!more) {
+ bitmap_fill(msk->pm.id_avail_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);
+ msk->pm.local_addr_used = 0;
+ }
spin_unlock_bh(&msk->pm.lock);
+
+ if (more)
+ goto again;
}
static void mptcp_nl_flush_addrs_list(struct net *net,
if (!mptcp_pm_is_userspace(msk)) {
lock_sock(sk);
- mptcp_pm_flush_addrs_and_subflows(msk, rm_list);
+ mptcp_pm_flush_addrs_and_subflows(msk, rm_list, NULL);
release_sock(sk);
}