aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/netlink/af_netlink.c130
1 files changed, 64 insertions, 66 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index a36777b7cfb6..155854802d44 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -2886,99 +2886,97 @@ EXPORT_SYMBOL(nlmsg_notify);
2886#ifdef CONFIG_PROC_FS 2886#ifdef CONFIG_PROC_FS
2887struct nl_seq_iter { 2887struct nl_seq_iter {
2888 struct seq_net_private p; 2888 struct seq_net_private p;
2889 struct rhashtable_iter hti;
2889 int link; 2890 int link;
2890 int hash_idx;
2891}; 2891};
2892 2892
2893static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) 2893static int netlink_walk_start(struct nl_seq_iter *iter)
2894{ 2894{
2895 struct nl_seq_iter *iter = seq->private; 2895 int err;
2896 int i, j;
2897 struct netlink_sock *nlk;
2898 struct sock *s;
2899 loff_t off = 0;
2900
2901 for (i = 0; i < MAX_LINKS; i++) {
2902 struct rhashtable *ht = &nl_table[i].hash;
2903 const struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht);
2904
2905 for (j = 0; j < tbl->size; j++) {
2906 struct rhash_head *node;
2907
2908 rht_for_each_entry_rcu(nlk, node, tbl, j, node) {
2909 s = (struct sock *)nlk;
2910 2896
2911 if (sock_net(s) != seq_file_net(seq)) 2897 err = rhashtable_walk_init(&nl_table[iter->link].hash, &iter->hti);
2912 continue; 2898 if (err) {
2913 if (off == pos) { 2899 iter->link = MAX_LINKS;
2914 iter->link = i; 2900 return err;
2915 iter->hash_idx = j;
2916 return s;
2917 }
2918 ++off;
2919 }
2920 }
2921 } 2901 }
2922 return NULL; 2902
2903 err = rhashtable_walk_start(&iter->hti);
2904 return err == -EAGAIN ? 0 : err;
2923} 2905}
2924 2906
2925static void *netlink_seq_start(struct seq_file *seq, loff_t *pos) 2907static void netlink_walk_stop(struct nl_seq_iter *iter)
2926 __acquires(RCU)
2927{ 2908{
2928 rcu_read_lock(); 2909 rhashtable_walk_stop(&iter->hti);
2929 return *pos ? netlink_seq_socket_idx(seq, *pos - 1) : SEQ_START_TOKEN; 2910 rhashtable_walk_exit(&iter->hti);
2930} 2911}
2931 2912
2932static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) 2913static void *__netlink_seq_next(struct seq_file *seq)
2933{ 2914{
2934 struct rhashtable *ht; 2915 struct nl_seq_iter *iter = seq->private;
2935 const struct bucket_table *tbl;
2936 struct rhash_head *node;
2937 struct netlink_sock *nlk; 2916 struct netlink_sock *nlk;
2938 struct nl_seq_iter *iter;
2939 struct net *net;
2940 int i, j;
2941 2917
2942 ++*pos; 2918 do {
2919 for (;;) {
2920 int err;
2943 2921
2944 if (v == SEQ_START_TOKEN) 2922 nlk = rhashtable_walk_next(&iter->hti);
2945 return netlink_seq_socket_idx(seq, 0);
2946 2923
2947 net = seq_file_net(seq); 2924 if (IS_ERR(nlk)) {
2948 iter = seq->private; 2925 if (PTR_ERR(nlk) == -EAGAIN)
2949 nlk = v; 2926 continue;
2950 2927
2951 i = iter->link; 2928 return nlk;
2952 ht = &nl_table[i].hash; 2929 }
2953 tbl = rht_dereference_rcu(ht->tbl, ht);
2954 rht_for_each_entry_rcu_continue(nlk, node, nlk->node.next, tbl, iter->hash_idx, node)
2955 if (net_eq(sock_net((struct sock *)nlk), net))
2956 return nlk;
2957 2930
2958 j = iter->hash_idx + 1; 2931 if (nlk)
2932 break;
2959 2933
2960 do { 2934 netlink_walk_stop(iter);
2935 if (++iter->link >= MAX_LINKS)
2936 return NULL;
2961 2937
2962 for (; j < tbl->size; j++) { 2938 err = netlink_walk_start(iter);
2963 rht_for_each_entry_rcu(nlk, node, tbl, j, node) { 2939 if (err)
2964 if (net_eq(sock_net((struct sock *)nlk), net)) { 2940 return ERR_PTR(err);
2965 iter->link = i;
2966 iter->hash_idx = j;
2967 return nlk;
2968 }
2969 }
2970 } 2941 }
2942 } while (sock_net(&nlk->sk) != seq_file_net(seq));
2971 2943
2972 j = 0; 2944 return nlk;
2973 } while (++i < MAX_LINKS); 2945}
2974 2946
2975 return NULL; 2947static void *netlink_seq_start(struct seq_file *seq, loff_t *posp)
2948{
2949 struct nl_seq_iter *iter = seq->private;
2950 void *obj = SEQ_START_TOKEN;
2951 loff_t pos;
2952 int err;
2953
2954 iter->link = 0;
2955
2956 err = netlink_walk_start(iter);
2957 if (err)
2958 return ERR_PTR(err);
2959
2960 for (pos = *posp; pos && obj && !IS_ERR(obj); pos--)
2961 obj = __netlink_seq_next(seq);
2962
2963 return obj;
2964}
2965
2966static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2967{
2968 ++*pos;
2969 return __netlink_seq_next(seq);
2976} 2970}
2977 2971
2978static void netlink_seq_stop(struct seq_file *seq, void *v) 2972static void netlink_seq_stop(struct seq_file *seq, void *v)
2979 __releases(RCU)
2980{ 2973{
2981 rcu_read_unlock(); 2974 struct nl_seq_iter *iter = seq->private;
2975
2976 if (iter->link >= MAX_LINKS)
2977 return;
2978
2979 netlink_walk_stop(iter);
2982} 2980}
2983 2981
2984 2982