]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - net/ipv6/ip6_fib.c
Merge tag 'sound-fix-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[linux.git] / net / ipv6 / ip6_fib.c
index 6e2af411cd9cc4131c5d457e6d48f177fc6d4428..7bae6a91b48726173ef285e0449a4bcb29d75993 100644 (file)
@@ -357,15 +357,17 @@ unsigned int fib6_tables_seq_read(struct net *net)
        return fib_seq;
 }
 
-static int call_fib6_entry_notifier(struct notifier_block *nb, struct net *net,
+static int call_fib6_entry_notifier(struct notifier_block *nb,
                                    enum fib_event_type event_type,
-                                   struct fib6_info *rt)
+                                   struct fib6_info *rt,
+                                   struct netlink_ext_ack *extack)
 {
        struct fib6_entry_notifier_info info = {
+               .info.extack = extack,
                .rt = rt,
        };
 
-       return call_fib6_notifier(nb, net, event_type, &info.info);
+       return call_fib6_notifier(nb, event_type, &info.info);
 }
 
 int call_fib6_entry_notifiers(struct net *net,
@@ -401,40 +403,51 @@ int call_fib6_multipath_entry_notifiers(struct net *net,
 struct fib6_dump_arg {
        struct net *net;
        struct notifier_block *nb;
+       struct netlink_ext_ack *extack;
 };
 
-static void fib6_rt_dump(struct fib6_info *rt, struct fib6_dump_arg *arg)
+static int fib6_rt_dump(struct fib6_info *rt, struct fib6_dump_arg *arg)
 {
        if (rt == arg->net->ipv6.fib6_null_entry)
-               return;
-       call_fib6_entry_notifier(arg->nb, arg->net, FIB_EVENT_ENTRY_ADD, rt);
+               return 0;
+       return call_fib6_entry_notifier(arg->nb, FIB_EVENT_ENTRY_ADD,
+                                       rt, arg->extack);
 }
 
 static int fib6_node_dump(struct fib6_walker *w)
 {
        struct fib6_info *rt;
+       int err = 0;
 
-       for_each_fib6_walker_rt(w)
-               fib6_rt_dump(rt, w->args);
+       for_each_fib6_walker_rt(w) {
+               err = fib6_rt_dump(rt, w->args);
+               if (err)
+                       break;
+       }
        w->leaf = NULL;
-       return 0;
+       return err;
 }
 
-static void fib6_table_dump(struct net *net, struct fib6_table *tb,
-                           struct fib6_walker *w)
+static int fib6_table_dump(struct net *net, struct fib6_table *tb,
+                          struct fib6_walker *w)
 {
+       int err;
+
        w->root = &tb->tb6_root;
        spin_lock_bh(&tb->tb6_lock);
-       fib6_walk(net, w);
+       err = fib6_walk(net, w);
        spin_unlock_bh(&tb->tb6_lock);
+       return err;
 }
 
 /* Called with rcu_read_lock() */
-int fib6_tables_dump(struct net *net, struct notifier_block *nb)
+int fib6_tables_dump(struct net *net, struct notifier_block *nb,
+                    struct netlink_ext_ack *extack)
 {
        struct fib6_dump_arg arg;
        struct fib6_walker *w;
        unsigned int h;
+       int err = 0;
 
        w = kzalloc(sizeof(*w), GFP_ATOMIC);
        if (!w)
@@ -443,19 +456,24 @@ int fib6_tables_dump(struct net *net, struct notifier_block *nb)
        w->func = fib6_node_dump;
        arg.net = net;
        arg.nb = nb;
+       arg.extack = extack;
        w->args = &arg;
 
        for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
                struct hlist_head *head = &net->ipv6.fib_table_hash[h];
                struct fib6_table *tb;
 
-               hlist_for_each_entry_rcu(tb, head, tb6_hlist)
-                       fib6_table_dump(net, tb, w);
+               hlist_for_each_entry_rcu(tb, head, tb6_hlist) {
+                       err = fib6_table_dump(net, tb, w);
+                       if (err < 0)
+                               goto out;
+               }
        }
 
+out:
        kfree(w);
 
-       return 0;
+       return err;
 }
 
 static int fib6_dump_node(struct fib6_walker *w)
@@ -1443,6 +1461,8 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt,
                }
 #endif
                goto failure;
+       } else if (fib6_requires_src(rt)) {
+               fib6_routes_require_src_inc(info->nl_net);
        }
        return err;
 
@@ -1915,6 +1935,8 @@ int fib6_del(struct fib6_info *rt, struct nl_info *info)
                struct fib6_info *cur = rcu_dereference_protected(*rtp,
                                        lockdep_is_held(&table->tb6_lock));
                if (rt == cur) {
+                       if (fib6_requires_src(cur))
+                               fib6_routes_require_src_dec(info->nl_net);
                        fib6_del_route(table, fn, rtp, info);
                        return 0;
                }