Commit 1f4c3dce authored by James Chapman's avatar James Chapman Committed by David S. Miller

l2tp: use get_next APIs for management requests and procfs/debugfs

l2tp netlink and procfs/debugfs iterate over tunnel and session lists
to obtain data. They currently use very inefficient get_nth functions
to do so. Replace these with get_next.

For netlink, use nl cb->ctx[] for passing state instead of the
obsolete cb->args[].

l2tp_tunnel_get_nth and l2tp_session_get_nth are no longer used so
they can be removed.
Signed-off-by: default avatarJames Chapman <jchapman@katalix.com>
Signed-off-by: default avatarTom Parkin <tparkin@katalix.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent aa92c1ce
...@@ -241,27 +241,6 @@ struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id) ...@@ -241,27 +241,6 @@ struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id)
} }
EXPORT_SYMBOL_GPL(l2tp_tunnel_get); EXPORT_SYMBOL_GPL(l2tp_tunnel_get);
struct l2tp_tunnel *l2tp_tunnel_get_nth(const struct net *net, int nth)
{
struct l2tp_net *pn = l2tp_pernet(net);
unsigned long tunnel_id, tmp;
struct l2tp_tunnel *tunnel;
int count = 0;
rcu_read_lock_bh();
idr_for_each_entry_ul(&pn->l2tp_tunnel_idr, tunnel, tmp, tunnel_id) {
if (tunnel && ++count > nth &&
refcount_inc_not_zero(&tunnel->ref_count)) {
rcu_read_unlock_bh();
return tunnel;
}
}
rcu_read_unlock_bh();
return NULL;
}
EXPORT_SYMBOL_GPL(l2tp_tunnel_get_nth);
struct l2tp_tunnel *l2tp_tunnel_get_next(const struct net *net, unsigned long *key) struct l2tp_tunnel *l2tp_tunnel_get_next(const struct net *net, unsigned long *key)
{ {
struct l2tp_net *pn = l2tp_pernet(net); struct l2tp_net *pn = l2tp_pernet(net);
...@@ -355,25 +334,6 @@ struct l2tp_session *l2tp_session_get(const struct net *net, struct sock *sk, in ...@@ -355,25 +334,6 @@ struct l2tp_session *l2tp_session_get(const struct net *net, struct sock *sk, in
} }
EXPORT_SYMBOL_GPL(l2tp_session_get); EXPORT_SYMBOL_GPL(l2tp_session_get);
struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth)
{
struct l2tp_session *session;
int count = 0;
rcu_read_lock_bh();
list_for_each_entry_rcu(session, &tunnel->session_list, list) {
if (++count > nth) {
l2tp_session_inc_refcount(session);
rcu_read_unlock_bh();
return session;
}
}
rcu_read_unlock_bh();
return NULL;
}
EXPORT_SYMBOL_GPL(l2tp_session_get_nth);
static struct l2tp_session *l2tp_v2_session_get_next(const struct net *net, static struct l2tp_session *l2tp_v2_session_get_next(const struct net *net,
u16 tid, u16 tid,
unsigned long *key) unsigned long *key)
......
...@@ -219,14 +219,12 @@ void l2tp_session_dec_refcount(struct l2tp_session *session); ...@@ -219,14 +219,12 @@ void l2tp_session_dec_refcount(struct l2tp_session *session);
* the caller must ensure that the reference is dropped appropriately. * the caller must ensure that the reference is dropped appropriately.
*/ */
struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id); struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id);
struct l2tp_tunnel *l2tp_tunnel_get_nth(const struct net *net, int nth);
struct l2tp_tunnel *l2tp_tunnel_get_next(const struct net *net, unsigned long *key); struct l2tp_tunnel *l2tp_tunnel_get_next(const struct net *net, unsigned long *key);
struct l2tp_session *l2tp_v3_session_get(const struct net *net, struct sock *sk, u32 session_id); struct l2tp_session *l2tp_v3_session_get(const struct net *net, struct sock *sk, u32 session_id);
struct l2tp_session *l2tp_v2_session_get(const struct net *net, u16 tunnel_id, u16 session_id); struct l2tp_session *l2tp_v2_session_get(const struct net *net, u16 tunnel_id, u16 session_id);
struct l2tp_session *l2tp_session_get(const struct net *net, struct sock *sk, int pver, struct l2tp_session *l2tp_session_get(const struct net *net, struct sock *sk, int pver,
u32 tunnel_id, u32 session_id); u32 tunnel_id, u32 session_id);
struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth);
struct l2tp_session *l2tp_session_get_next(const struct net *net, struct sock *sk, int pver, struct l2tp_session *l2tp_session_get_next(const struct net *net, struct sock *sk, int pver,
u32 tunnel_id, unsigned long *key); u32 tunnel_id, unsigned long *key);
struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net, struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net,
......
...@@ -34,8 +34,8 @@ static struct dentry *rootdir; ...@@ -34,8 +34,8 @@ static struct dentry *rootdir;
struct l2tp_dfs_seq_data { struct l2tp_dfs_seq_data {
struct net *net; struct net *net;
netns_tracker ns_tracker; netns_tracker ns_tracker;
int tunnel_idx; /* current tunnel */ unsigned long tkey; /* lookup key of current tunnel */
int session_idx; /* index of session within current tunnel */ unsigned long skey; /* lookup key of current session */
struct l2tp_tunnel *tunnel; struct l2tp_tunnel *tunnel;
struct l2tp_session *session; /* NULL means get next tunnel */ struct l2tp_session *session; /* NULL means get next tunnel */
}; };
...@@ -46,8 +46,8 @@ static void l2tp_dfs_next_tunnel(struct l2tp_dfs_seq_data *pd) ...@@ -46,8 +46,8 @@ static void l2tp_dfs_next_tunnel(struct l2tp_dfs_seq_data *pd)
if (pd->tunnel) if (pd->tunnel)
l2tp_tunnel_dec_refcount(pd->tunnel); l2tp_tunnel_dec_refcount(pd->tunnel);
pd->tunnel = l2tp_tunnel_get_nth(pd->net, pd->tunnel_idx); pd->tunnel = l2tp_tunnel_get_next(pd->net, &pd->tkey);
pd->tunnel_idx++; pd->tkey++;
} }
static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd) static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd)
...@@ -56,11 +56,13 @@ static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd) ...@@ -56,11 +56,13 @@ static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd)
if (pd->session) if (pd->session)
l2tp_session_dec_refcount(pd->session); l2tp_session_dec_refcount(pd->session);
pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx); pd->session = l2tp_session_get_next(pd->net, pd->tunnel->sock,
pd->session_idx++; pd->tunnel->version,
pd->tunnel->tunnel_id, &pd->skey);
pd->skey++;
if (!pd->session) { if (!pd->session) {
pd->session_idx = 0; pd->skey = 0;
l2tp_dfs_next_tunnel(pd); l2tp_dfs_next_tunnel(pd);
} }
} }
......
...@@ -491,14 +491,20 @@ static int l2tp_nl_cmd_tunnel_get(struct sk_buff *skb, struct genl_info *info) ...@@ -491,14 +491,20 @@ static int l2tp_nl_cmd_tunnel_get(struct sk_buff *skb, struct genl_info *info)
return ret; return ret;
} }
struct l2tp_nl_cb_data {
unsigned long tkey;
unsigned long skey;
};
static int l2tp_nl_cmd_tunnel_dump(struct sk_buff *skb, struct netlink_callback *cb) static int l2tp_nl_cmd_tunnel_dump(struct sk_buff *skb, struct netlink_callback *cb)
{ {
int ti = cb->args[0]; struct l2tp_nl_cb_data *cbd = (void *)&cb->ctx[0];
unsigned long key = cbd->tkey;
struct l2tp_tunnel *tunnel; struct l2tp_tunnel *tunnel;
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
for (;;) { for (;;) {
tunnel = l2tp_tunnel_get_nth(net, ti); tunnel = l2tp_tunnel_get_next(net, &key);
if (!tunnel) if (!tunnel)
goto out; goto out;
...@@ -510,11 +516,11 @@ static int l2tp_nl_cmd_tunnel_dump(struct sk_buff *skb, struct netlink_callback ...@@ -510,11 +516,11 @@ static int l2tp_nl_cmd_tunnel_dump(struct sk_buff *skb, struct netlink_callback
} }
l2tp_tunnel_dec_refcount(tunnel); l2tp_tunnel_dec_refcount(tunnel);
ti++; key++;
} }
out: out:
cb->args[0] = ti; cbd->tkey = key;
return skb->len; return skb->len;
} }
...@@ -832,25 +838,27 @@ static int l2tp_nl_cmd_session_get(struct sk_buff *skb, struct genl_info *info) ...@@ -832,25 +838,27 @@ static int l2tp_nl_cmd_session_get(struct sk_buff *skb, struct genl_info *info)
static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback *cb) static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback *cb)
{ {
struct l2tp_nl_cb_data *cbd = (void *)&cb->ctx[0];
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
struct l2tp_session *session; struct l2tp_session *session;
struct l2tp_tunnel *tunnel = NULL; struct l2tp_tunnel *tunnel = NULL;
int ti = cb->args[0]; unsigned long tkey = cbd->tkey;
int si = cb->args[1]; unsigned long skey = cbd->skey;
for (;;) { for (;;) {
if (!tunnel) { if (!tunnel) {
tunnel = l2tp_tunnel_get_nth(net, ti); tunnel = l2tp_tunnel_get_next(net, &tkey);
if (!tunnel) if (!tunnel)
goto out; goto out;
} }
session = l2tp_session_get_nth(tunnel, si); session = l2tp_session_get_next(net, tunnel->sock, tunnel->version,
tunnel->tunnel_id, &skey);
if (!session) { if (!session) {
ti++; tkey++;
l2tp_tunnel_dec_refcount(tunnel); l2tp_tunnel_dec_refcount(tunnel);
tunnel = NULL; tunnel = NULL;
si = 0; skey = 0;
continue; continue;
} }
...@@ -863,12 +871,12 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback ...@@ -863,12 +871,12 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback
} }
l2tp_session_dec_refcount(session); l2tp_session_dec_refcount(session);
si++; skey++;
} }
out: out:
cb->args[0] = ti; cbd->tkey = tkey;
cb->args[1] = si; cbd->skey = skey;
return skb->len; return skb->len;
} }
......
...@@ -1397,8 +1397,8 @@ static int pppol2tp_getsockopt(struct socket *sock, int level, int optname, ...@@ -1397,8 +1397,8 @@ static int pppol2tp_getsockopt(struct socket *sock, int level, int optname,
struct pppol2tp_seq_data { struct pppol2tp_seq_data {
struct seq_net_private p; struct seq_net_private p;
int tunnel_idx; /* current tunnel */ unsigned long tkey; /* lookup key of current tunnel */
int session_idx; /* index of session within current tunnel */ unsigned long skey; /* lookup key of current session */
struct l2tp_tunnel *tunnel; struct l2tp_tunnel *tunnel;
struct l2tp_session *session; /* NULL means get next tunnel */ struct l2tp_session *session; /* NULL means get next tunnel */
}; };
...@@ -1410,8 +1410,8 @@ static void pppol2tp_next_tunnel(struct net *net, struct pppol2tp_seq_data *pd) ...@@ -1410,8 +1410,8 @@ static void pppol2tp_next_tunnel(struct net *net, struct pppol2tp_seq_data *pd)
l2tp_tunnel_dec_refcount(pd->tunnel); l2tp_tunnel_dec_refcount(pd->tunnel);
for (;;) { for (;;) {
pd->tunnel = l2tp_tunnel_get_nth(net, pd->tunnel_idx); pd->tunnel = l2tp_tunnel_get_next(net, &pd->tkey);
pd->tunnel_idx++; pd->tkey++;
/* Only accept L2TPv2 tunnels */ /* Only accept L2TPv2 tunnels */
if (!pd->tunnel || pd->tunnel->version == 2) if (!pd->tunnel || pd->tunnel->version == 2)
...@@ -1427,11 +1427,13 @@ static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd) ...@@ -1427,11 +1427,13 @@ static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd)
if (pd->session) if (pd->session)
l2tp_session_dec_refcount(pd->session); l2tp_session_dec_refcount(pd->session);
pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx); pd->session = l2tp_session_get_next(net, pd->tunnel->sock,
pd->session_idx++; pd->tunnel->version,
pd->tunnel->tunnel_id, &pd->skey);
pd->skey++;
if (!pd->session) { if (!pd->session) {
pd->session_idx = 0; pd->skey = 0;
pppol2tp_next_tunnel(net, pd); pppol2tp_next_tunnel(net, pd);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment