]> Git Repo - linux.git/commitdiff
Merge tag 'sysctl-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof...
authorLinus Torvalds <[email protected]>
Wed, 30 Aug 2023 00:39:15 +0000 (17:39 -0700)
committerLinus Torvalds <[email protected]>
Wed, 30 Aug 2023 00:39:15 +0000 (17:39 -0700)
Pull sysctl updates from Luis Chamberlain:
 "Long ago we set out to remove the kitchen sink on kernel/sysctl.c
  arrays and placings sysctls to their own sybsystem or file to help
  avoid merge conflicts. Matthew Wilcox pointed out though that if we're
  going to do that we might as well also *save* space while at it and
  try to remove the extra last sysctl entry added at the end of each
  array, a sentintel, instead of bloating the kernel by adding a new
  sentinel with each array moved.

  Doing that was not so trivial, and has required slowing down the moves
  of kernel/sysctl.c arrays and measuring the impact on size by each new
  move.

  The complex part of the effort to help reduce the size of each sysctl
  is being done by the patient work of el seƱor Don Joel Granados. A lot
  of this is truly painful code refactoring and testing and then trying
  to measure the savings of each move and removing the sentinels.
  Although Joel already has code which does most of this work,
  experience with sysctl moves in the past shows is we need to be
  careful due to the slew of odd build failures that are possible due to
  the amount of random Kconfig options sysctls use.

  To that end Joel's work is split by first addressing the major
  housekeeping needed to remove the sentinels, which is part of this
  merge request. The rest of the work to actually remove the sentinels
  will be done later in future kernel releases.

  The preliminary math is showing this will all help reduce the overall
  build time size of the kernel and run time memory consumed by the
  kernel by about ~64 bytes per array where we are able to remove each
  sentinel in the future. That also means there is no more bloating the
  kernel with the extra ~64 bytes per array moved as no new sentinels
  are created"

* tag 'sysctl-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux:
  sysctl: Use ctl_table_size as stopping criteria for list macro
  sysctl: SIZE_MAX->ARRAY_SIZE in register_net_sysctl
  vrf: Update to register_net_sysctl_sz
  networking: Update to register_net_sysctl_sz
  netfilter: Update to register_net_sysctl_sz
  ax.25: Update to register_net_sysctl_sz
  sysctl: Add size to register_net_sysctl function
  sysctl: Add size arg to __register_sysctl_init
  sysctl: Add size to register_sysctl
  sysctl: Add a size arg to __register_sysctl_table
  sysctl: Add size argument to init_header
  sysctl: Add ctl_table_size to ctl_table_header
  sysctl: Use ctl_table_header in list_for_each_table_entry
  sysctl: Prefer ctl_table_header in proc_sysctl

14 files changed:
1  2 
drivers/net/vrf.c
fs/proc/proc_sysctl.c
include/net/ipv6.h
include/net/net_namespace.h
net/ipv4/devinet.c
net/ipv4/route.c
net/ipv4/xfrm4_policy.c
net/ipv6/addrconf.c
net/ipv6/icmp.c
net/ipv6/route.c
net/ipv6/xfrm6_policy.c
net/mptcp/ctrl.c
net/netfilter/ipvs/ip_vs_ctl.c
net/smc/smc_sysctl.c

diff --combined drivers/net/vrf.c
index 43f374444684d86e4125b7c6c749249c446a8b13,f4c3df15a0e539deb4b8001c7d4560b38d9eaaca..a3408e4e1491bbc16d36fc9ce681201b4928cc08
@@@ -638,7 -638,9 +638,7 @@@ static void vrf_finish_direct(struct sk
                eth_zero_addr(eth->h_dest);
                eth->h_proto = skb->protocol;
  
 -              rcu_read_lock_bh();
                dev_queue_xmit_nit(skb, vrf_dev);
 -              rcu_read_unlock_bh();
  
                skb_pull(skb, ETH_HLEN);
        }
@@@ -662,7 -664,7 +662,7 @@@ static int vrf_finish_output6(struct ne
        skb->protocol = htons(ETH_P_IPV6);
        skb->dev = dev;
  
 -      rcu_read_lock_bh();
 +      rcu_read_lock();
        nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr);
        neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop);
        if (unlikely(!neigh))
        if (!IS_ERR(neigh)) {
                sock_confirm_neigh(skb, neigh);
                ret = neigh_output(neigh, skb, false);
 -              rcu_read_unlock_bh();
 +              rcu_read_unlock();
                return ret;
        }
 -      rcu_read_unlock_bh();
 +      rcu_read_unlock();
  
        IP6_INC_STATS(dev_net(dst->dev),
                      ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
@@@ -887,7 -889,7 +887,7 @@@ static int vrf_finish_output(struct ne
                }
        }
  
 -      rcu_read_lock_bh();
 +      rcu_read_lock();
  
        neigh = ip_neigh_for_gw(rt, skb, &is_v6gw);
        if (!IS_ERR(neigh)) {
                sock_confirm_neigh(skb, neigh);
                /* if crossing protocols, can not use the cached header */
                ret = neigh_output(neigh, skb, is_v6gw);
 -              rcu_read_unlock_bh();
 +              rcu_read_unlock();
                return ret;
        }
  
 -      rcu_read_unlock_bh();
 +      rcu_read_unlock();
        vrf_tx_error(skb->dev, skb);
        return -EINVAL;
  }
@@@ -1977,7 -1979,8 +1977,8 @@@ static int vrf_netns_init_sysctl(struc
        /* init the extra1 parameter with the reference to current netns */
        table[0].extra1 = net;
  
-       nn_vrf->ctl_hdr = register_net_sysctl(net, "net/vrf", table);
+       nn_vrf->ctl_hdr = register_net_sysctl_sz(net, "net/vrf", table,
+                                                ARRAY_SIZE(vrf_table));
        if (!nn_vrf->ctl_hdr) {
                kfree(table);
                return -ENOMEM;
diff --combined fs/proc/proc_sysctl.c
index bf06344a42cc6af622033fd47e5ac5d4a19bd4b4,504e847c2a3a6b15f4e9bac29bbb7297b85c4ea3..c88854df0b624f7c251fbec7e9806f1ef7ef9a1b
@@@ -19,8 -19,9 +19,9 @@@
  #include <linux/kmemleak.h>
  #include "internal.h"
  
- #define list_for_each_table_entry(entry, table) \
-       for ((entry) = (table); (entry)->procname; (entry)++)
+ #define list_for_each_table_entry(entry, header)      \
+       entry = header->ctl_table;                      \
+       for (size_t i = 0 ; i < header->ctl_table_size && entry->procname; ++i, entry++)
  
  static const struct dentry_operations proc_sys_dentry_operations;
  static const struct file_operations proc_sys_file_operations;
@@@ -43,7 -44,7 +44,7 @@@ static struct ctl_table sysctl_mount_po
   */
  struct ctl_table_header *register_sysctl_mount_point(const char *path)
  {
-       return register_sysctl(path, sysctl_mount_point);
+       return register_sysctl_sz(path, sysctl_mount_point, 0);
  }
  EXPORT_SYMBOL(register_sysctl_mount_point);
  
@@@ -188,9 -189,10 +189,10 @@@ static void erase_entry(struct ctl_tabl
  
  static void init_header(struct ctl_table_header *head,
        struct ctl_table_root *root, struct ctl_table_set *set,
-       struct ctl_node *node, struct ctl_table *table)
+       struct ctl_node *node, struct ctl_table *table, size_t table_size)
  {
        head->ctl_table = table;
+       head->ctl_table_size = table_size;
        head->ctl_table_arg = table;
        head->used = 0;
        head->count = 1;
        if (node) {
                struct ctl_table *entry;
  
-               list_for_each_table_entry(entry, table) {
+               list_for_each_table_entry(entry, head) {
                        node->header = head;
                        node++;
                }
@@@ -215,7 -217,7 +217,7 @@@ static void erase_header(struct ctl_tab
  {
        struct ctl_table *entry;
  
-       list_for_each_table_entry(entry, head->ctl_table)
+       list_for_each_table_entry(entry, head)
                erase_entry(head, entry);
  }
  
@@@ -242,7 -244,7 +244,7 @@@ static int insert_header(struct ctl_di
        err = insert_links(header);
        if (err)
                goto fail_links;
-       list_for_each_table_entry(entry, header->ctl_table) {
+       list_for_each_table_entry(entry, header) {
                err = insert_entry(header, entry);
                if (err)
                        goto fail;
@@@ -463,7 -465,7 +465,7 @@@ static struct inode *proc_sys_make_inod
        head->count++;
        spin_unlock(&sysctl_lock);
  
 -      inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
 +      inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode);
        inode->i_mode = table->mode;
        if (!S_ISDIR(table->mode)) {
                inode->i_mode |= S_IFREG;
@@@ -849,7 -851,7 +851,7 @@@ static int proc_sys_getattr(struct mnt_
        if (IS_ERR(head))
                return PTR_ERR(head);
  
 -      generic_fillattr(&nop_mnt_idmap, inode, stat);
 +      generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
        if (table)
                stat->mode = (stat->mode & S_IFMT) | table->mode;
  
@@@ -973,7 -975,7 +975,7 @@@ static struct ctl_dir *new_dir(struct c
        memcpy(new_name, name, namelen);
        table[0].procname = new_name;
        table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO;
-       init_header(&new->header, set->dir.header.root, set, node, table);
+       init_header(&new->header, set->dir.header.root, set, node, table, 1);
  
        return new;
  }
@@@ -1125,11 -1127,11 +1127,11 @@@ static int sysctl_check_table_array(con
        return err;
  }
  
- static int sysctl_check_table(const char *path, struct ctl_table *table)
+ static int sysctl_check_table(const char *path, struct ctl_table_header *header)
  {
        struct ctl_table *entry;
        int err = 0;
-       list_for_each_table_entry(entry, table) {
+       list_for_each_table_entry(entry, header) {
                if ((entry->proc_handler == proc_dostring) ||
                    (entry->proc_handler == proc_dobool) ||
                    (entry->proc_handler == proc_dointvec) ||
        return err;
  }
  
- static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table *table,
-       struct ctl_table_root *link_root)
+ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table_header *head)
  {
        struct ctl_table *link_table, *entry, *link;
        struct ctl_table_header *links;
  
        name_bytes = 0;
        nr_entries = 0;
-       list_for_each_table_entry(entry, table) {
+       list_for_each_table_entry(entry, head) {
                nr_entries++;
                name_bytes += strlen(entry->procname) + 1;
        }
        link_name = (char *)&link_table[nr_entries + 1];
        link = link_table;
  
-       list_for_each_table_entry(entry, table) {
+       list_for_each_table_entry(entry, head) {
                int len = strlen(entry->procname) + 1;
                memcpy(link_name, entry->procname, len);
                link->procname = link_name;
                link->mode = S_IFLNK|S_IRWXUGO;
-               link->data = link_root;
+               link->data = head->root;
                link_name += len;
                link++;
        }
-       init_header(links, dir->header.root, dir->header.set, node, link_table);
+       init_header(links, dir->header.root, dir->header.set, node, link_table,
+                   head->ctl_table_size);
        links->nreg = nr_entries;
  
        return links;
  }
  
  static bool get_links(struct ctl_dir *dir,
-       struct ctl_table *table, struct ctl_table_root *link_root)
+                     struct ctl_table_header *header,
+                     struct ctl_table_root *link_root)
  {
-       struct ctl_table_header *head;
+       struct ctl_table_header *tmp_head;
        struct ctl_table *entry, *link;
  
        /* Are there links available for every entry in table? */
-       list_for_each_table_entry(entry, table) {
+       list_for_each_table_entry(entry, header) {
                const char *procname = entry->procname;
-               link = find_entry(&head, dir, procname, strlen(procname));
+               link = find_entry(&tmp_head, dir, procname, strlen(procname));
                if (!link)
                        return false;
                if (S_ISDIR(link->mode) && S_ISDIR(entry->mode))
        }
  
        /* The checks passed.  Increase the registration count on the links */
-       list_for_each_table_entry(entry, table) {
+       list_for_each_table_entry(entry, header) {
                const char *procname = entry->procname;
-               link = find_entry(&head, dir, procname, strlen(procname));
-               head->nreg++;
+               link = find_entry(&tmp_head, dir, procname, strlen(procname));
+               tmp_head->nreg++;
        }
        return true;
  }
@@@ -1246,13 -1249,13 +1249,13 @@@ static int insert_links(struct ctl_tabl
        if (IS_ERR(core_parent))
                return 0;
  
-       if (get_links(core_parent, head->ctl_table, head->root))
+       if (get_links(core_parent, head, head->root))
                return 0;
  
        core_parent->header.nreg++;
        spin_unlock(&sysctl_lock);
  
-       links = new_links(core_parent, head->ctl_table, head->root);
+       links = new_links(core_parent, head);
  
        spin_lock(&sysctl_lock);
        err = -ENOMEM;
                goto out;
  
        err = 0;
-       if (get_links(core_parent, head->ctl_table, head->root)) {
+       if (get_links(core_parent, head, head->root)) {
                kfree(links);
                goto out;
        }
@@@ -1310,6 -1313,7 +1313,7 @@@ static struct ctl_dir *sysctl_mkdir_p(s
   *     should not be free'd after registration. So it should not be
   *     used on stack. It can either be a global or dynamically allocated
   *     by the caller and free'd later after sysctl unregistration.
+  * @table_size : The number of elements in table
   *
   * Register a sysctl table hierarchy. @table should be a filled in ctl_table
   * array. A completely 0 filled entry terminates the table.
   */
  struct ctl_table_header *__register_sysctl_table(
        struct ctl_table_set *set,
-       const char *path, struct ctl_table *table)
+       const char *path, struct ctl_table *table, size_t table_size)
  {
        struct ctl_table_root *root = set->dir.header.root;
        struct ctl_table_header *header;
        struct ctl_dir *dir;
-       struct ctl_table *entry;
        struct ctl_node *node;
-       int nr_entries = 0;
-       list_for_each_table_entry(entry, table)
-               nr_entries++;
  
        header = kzalloc(sizeof(struct ctl_table_header) +
-                        sizeof(struct ctl_node)*nr_entries, GFP_KERNEL_ACCOUNT);
+                        sizeof(struct ctl_node)*table_size, GFP_KERNEL_ACCOUNT);
        if (!header)
                return NULL;
  
        node = (struct ctl_node *)(header + 1);
-       init_header(header, root, set, node, table);
-       if (sysctl_check_table(path, table))
+       init_header(header, root, set, node, table, table_size);
+       if (sysctl_check_table(path, header))
                goto fail;
  
        spin_lock(&sysctl_lock);
@@@ -1401,7 -1400,7 +1400,7 @@@ fail
  }
  
  /**
-  * register_sysctl - register a sysctl table
+  * register_sysctl_sz - register a sysctl table
   * @path: The path to the directory the sysctl table is in. If the path
   *    doesn't exist we will create it for you.
   * @table: the table structure. The calller must ensure the life of the @table
   *    to call unregister_sysctl_table() and can instead use something like
   *    register_sysctl_init() which does not care for the result of the syctl
   *    registration.
+  * @table_size: The number of elements in table.
   *
   * Register a sysctl table. @table should be a filled in ctl_table
   * array. A completely 0 filled entry terminates the table.
   *
   * See __register_sysctl_table for more details.
   */
- struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table)
+ struct ctl_table_header *register_sysctl_sz(const char *path, struct ctl_table *table,
+                                           size_t table_size)
  {
        return __register_sysctl_table(&sysctl_table_root.default_set,
-                                       path, table);
+                                       path, table, table_size);
  }
- EXPORT_SYMBOL(register_sysctl);
+ EXPORT_SYMBOL(register_sysctl_sz);
  
  /**
   * __register_sysctl_init() - register sysctl table to path
   *    lifetime use of the sysctl.
   * @table_name: The name of sysctl table, only used for log printing when
   *              registration fails
+  * @table_size: The number of elements in table
   *
   * The sysctl interface is used by userspace to query or modify at runtime
   * a predefined value set on a variable. These variables however have default
   * Context: if your base directory does not exist it will be created for you.
   */
  void __init __register_sysctl_init(const char *path, struct ctl_table *table,
-                                const char *table_name)
+                                const char *table_name, size_t table_size)
  {
-       struct ctl_table_header *hdr = register_sysctl(path, table);
+       struct ctl_table_header *hdr = register_sysctl_sz(path, table, table_size);
  
        if (unlikely(!hdr)) {
-               pr_err("failed when register_sysctl %s to %s\n", table_name, path);
+               pr_err("failed when register_sysctl_sz %s to %s\n", table_name, path);
                return;
        }
        kmemleak_not_leak(hdr);
@@@ -1471,7 -1473,7 +1473,7 @@@ static void put_links(struct ctl_table_
        if (IS_ERR(core_parent))
                return;
  
-       list_for_each_table_entry(entry, header->ctl_table) {
+       list_for_each_table_entry(entry, header) {
                struct ctl_table_header *link_head;
                struct ctl_table *link;
                const char *name = entry->procname;
@@@ -1535,7 -1537,7 +1537,7 @@@ void setup_sysctl_set(struct ctl_table_
  {
        memset(set, 0, sizeof(*set));
        set->is_seen = is_seen;
-       init_header(&set->dir.header, root, set, NULL, root_table);
+       init_header(&set->dir.header, root, set, NULL, root_table, 1);
  }
  
  void retire_sysctl_set(struct ctl_table_set *set)
diff --combined include/net/ipv6.h
index d40d8238d4c2b9881dbbc17b37898a84050e401f,63ba68536a20d9ffd0534b37485232274de3cbf9..0675be0f3fa0efc55575bb5b2569dc8a1dbb9f24
@@@ -752,8 -752,12 +752,8 @@@ static inline u32 ipv6_addr_hash(const 
  /* more secured version of ipv6_addr_hash() */
  static inline u32 __ipv6_addr_jhash(const struct in6_addr *a, const u32 initval)
  {
 -      u32 v = (__force u32)a->s6_addr32[0] ^ (__force u32)a->s6_addr32[1];
 -
 -      return jhash_3words(v,
 -                          (__force u32)a->s6_addr32[2],
 -                          (__force u32)a->s6_addr32[3],
 -                          initval);
 +      return jhash2((__force const u32 *)a->s6_addr32,
 +                    ARRAY_SIZE(a->s6_addr32), initval);
  }
  
  static inline bool ipv6_addr_loopback(const struct in6_addr *a)
@@@ -937,8 -941,7 +937,8 @@@ static inline bool ipv6_can_nonlocal_bi
                                          struct inet_sock *inet)
  {
        return net->ipv6.sysctl.ip_nonlocal_bind ||
 -              inet->freebind || inet->transparent;
 +              test_bit(INET_FLAGS_FREEBIND, &inet->inet_flags) ||
 +              test_bit(INET_FLAGS_TRANSPARENT, &inet->inet_flags);
  }
  
  /* Sysctl settings for net ipv6.auto_flowlabels */
@@@ -1217,7 -1220,6 +1217,7 @@@ void inet6_cleanup_sock(struct sock *sk
  void inet6_sock_destruct(struct sock *sk);
  int inet6_release(struct socket *sock);
  int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len);
 +int inet6_bind_sk(struct sock *sk, struct sockaddr *uaddr, int addr_len);
  int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
                  int peer);
  int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
@@@ -1272,7 -1274,9 +1272,9 @@@ static inline int snmp6_unregister_dev(
  
  #ifdef CONFIG_SYSCTL
  struct ctl_table *ipv6_icmp_sysctl_init(struct net *net);
+ size_t ipv6_icmp_sysctl_table_size(void);
  struct ctl_table *ipv6_route_sysctl_init(struct net *net);
+ size_t ipv6_route_sysctl_table_size(struct net *net);
  int ipv6_sysctl_register(void);
  void ipv6_sysctl_unregister(void);
  #endif
index 9f6add96de2d76c353932c2a31d83075b65f7dab,75dba309e0434df30bd55c7cc28ea29a9cc94810..eb6cd43b1746387b7e9dd87b62272e5b92b880cc
@@@ -42,7 -42,6 +42,7 @@@
  #include <linux/idr.h>
  #include <linux/skbuff.h>
  #include <linux/notifier.h>
 +#include <linux/xarray.h>
  
  struct user_namespace;
  struct proc_dir_entry;
@@@ -70,7 -69,7 +70,7 @@@ struct net 
        atomic_t                dev_unreg_count;
  
        unsigned int            dev_base_seq;   /* protected by rtnl_mutex */
 -      int                     ifindex;
 +      u32                     ifindex;
  
        spinlock_t              nsid_lock;
        atomic_t                fnhe_genid;
  
        struct hlist_head       *dev_name_head;
        struct hlist_head       *dev_index_head;
 +      struct xarray           dev_by_index;
        struct raw_notifier_head        netdev_chain;
  
        /* Note that @hash_mix can be read millions times per second,
@@@ -471,15 -469,17 +471,17 @@@ void unregister_pernet_device(struct pe
  
  struct ctl_table;
  
+ #define register_net_sysctl(net, path, table) \
+       register_net_sysctl_sz(net, path, table, ARRAY_SIZE(table))
  #ifdef CONFIG_SYSCTL
  int net_sysctl_init(void);
- struct ctl_table_header *register_net_sysctl(struct net *net, const char *path,
-                                            struct ctl_table *table);
+ struct ctl_table_header *register_net_sysctl_sz(struct net *net, const char *path,
+                                            struct ctl_table *table, size_t table_size);
  void unregister_net_sysctl_table(struct ctl_table_header *header);
  #else
  static inline int net_sysctl_init(void) { return 0; }
- static inline struct ctl_table_header *register_net_sysctl(struct net *net,
-       const char *path, struct ctl_table *table)
+ static inline struct ctl_table_header *register_net_sysctl_sz(struct net *net,
+       const char *path, struct ctl_table *table, size_t table_size)
  {
        return NULL;
  }
diff --combined net/ipv4/devinet.c
index c3658b8755bca5ea08e8b8f1fc08709dbc24d221,89087844ea6eae385df27020415134fd62cf4bde..9cf64ee47dd2b4fddf7be62c7110a1ad41b53fe8
@@@ -509,7 -509,6 +509,7 @@@ static int __inet_insert_ifa(struct in_
                                return -EEXIST;
                        }
                        if (ifa1->ifa_scope != ifa->ifa_scope) {
 +                              NL_SET_ERR_MSG(extack, "ipv4: Invalid scope value");
                                inet_free_ifa(ifa);
                                return -EINVAL;
                        }
@@@ -665,7 -664,6 +665,7 @@@ static int inet_rtm_deladdr(struct sk_b
        ifm = nlmsg_data(nlh);
        in_dev = inetdev_by_index(net, ifm->ifa_index);
        if (!in_dev) {
 +              NL_SET_ERR_MSG(extack, "ipv4: Device not found");
                err = -ENODEV;
                goto errout;
        }
                return 0;
        }
  
 +      NL_SET_ERR_MSG(extack, "ipv4: Address not found");
        err = -EADDRNOTAVAIL;
  errout:
        return err;
@@@ -842,23 -839,13 +842,23 @@@ static struct in_ifaddr *rtm_to_ifaddr(
  
        ifm = nlmsg_data(nlh);
        err = -EINVAL;
 -      if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL])
 +
 +      if (ifm->ifa_prefixlen > 32) {
 +              NL_SET_ERR_MSG(extack, "ipv4: Invalid prefix length");
                goto errout;
 +      }
 +
 +      if (!tb[IFA_LOCAL]) {
 +              NL_SET_ERR_MSG(extack, "ipv4: Local address is not supplied");
 +              goto errout;
 +      }
  
        dev = __dev_get_by_index(net, ifm->ifa_index);
        err = -ENODEV;
 -      if (!dev)
 +      if (!dev) {
 +              NL_SET_ERR_MSG(extack, "ipv4: Device not found");
                goto errout;
 +      }
  
        in_dev = __in_dev_get_rtnl(dev);
        err = -ENOBUFS;
  
                ci = nla_data(tb[IFA_CACHEINFO]);
                if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
 +                      NL_SET_ERR_MSG(extack, "ipv4: address lifetime invalid");
                        err = -EINVAL;
                        goto errout_free;
                }
@@@ -968,7 -954,6 +968,7 @@@ static int inet_rtm_newaddr(struct sk_b
                        int ret = ip_mc_autojoin_config(net, true, ifa);
  
                        if (ret < 0) {
 +                              NL_SET_ERR_MSG(extack, "ipv4: Multicast auto join failed");
                                inet_free_ifa(ifa);
                                return ret;
                        }
                inet_free_ifa(ifa);
  
                if (nlh->nlmsg_flags & NLM_F_EXCL ||
 -                  !(nlh->nlmsg_flags & NLM_F_REPLACE))
 +                  !(nlh->nlmsg_flags & NLM_F_REPLACE)) {
 +                      NL_SET_ERR_MSG(extack, "ipv4: Address already assigned");
                        return -EEXIST;
 +              }
                ifa = ifa_existing;
  
                if (ifa->ifa_rt_priority != new_metric) {
@@@ -2737,7 -2720,8 +2737,8 @@@ static __net_init int devinet_init_net(
                goto err_reg_dflt;
  
        err = -ENOMEM;
-       forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
+       forw_hdr = register_net_sysctl_sz(net, "net/ipv4", tbl,
+                                         ARRAY_SIZE(ctl_forward_entry));
        if (!forw_hdr)
                goto err_reg_ctl;
        net->ipv4.forw_hdr = forw_hdr;
diff --combined net/ipv4/route.c
index a4e153dd615ba9321d8252a5026acafaa294a149,e7e9fba0357a72b164790d7ddf80c5e14b375021..d8c99bdc617061b4790f87dce138348ae4cfa3c7
@@@ -515,12 -515,13 +515,12 @@@ static void __build_flow_key(const stru
        __u8 scope = RT_SCOPE_UNIVERSE;
  
        if (sk) {
 -              const struct inet_sock *inet = inet_sk(sk);
 -
                oif = sk->sk_bound_dev_if;
 -              mark = sk->sk_mark;
 +              mark = READ_ONCE(sk->sk_mark);
                tos = ip_sock_rt_tos(sk);
                scope = ip_sock_rt_scope(sk);
 -              prot = inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol;
 +              prot = inet_test_bit(HDRINCL, sk) ? IPPROTO_RAW :
 +                                                  sk->sk_protocol;
        }
  
        flowi4_init_output(fl4, oif, mark, tos & IPTOS_RT_MASK, scope,
@@@ -551,11 -552,10 +551,11 @@@ static void build_sk_flow_key(struct fl
        inet_opt = rcu_dereference(inet->inet_opt);
        if (inet_opt && inet_opt->opt.srr)
                daddr = inet_opt->opt.faddr;
 -      flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark,
 +      flowi4_init_output(fl4, sk->sk_bound_dev_if, READ_ONCE(sk->sk_mark),
                           ip_sock_rt_tos(sk) & IPTOS_RT_MASK,
                           ip_sock_rt_scope(sk),
 -                         inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
 +                         inet_test_bit(HDRINCL, sk) ?
 +                              IPPROTO_RAW : sk->sk_protocol,
                           inet_sk_flowi_flags(sk),
                           daddr, inet->inet_saddr, 0, 0, sk->sk_uid);
        rcu_read_unlock();
@@@ -3592,6 -3592,7 +3592,7 @@@ static struct ctl_table ipv4_route_netn
  static __net_init int sysctl_route_net_init(struct net *net)
  {
        struct ctl_table *tbl;
+       size_t table_size = ARRAY_SIZE(ipv4_route_netns_table);
  
        tbl = ipv4_route_netns_table;
        if (!net_eq(net, &init_net)) {
  
                /* Don't export non-whitelisted sysctls to unprivileged users */
                if (net->user_ns != &init_user_ns) {
-                       if (tbl[0].procname != ipv4_route_flush_procname)
+                       if (tbl[0].procname != ipv4_route_flush_procname) {
                                tbl[0].procname = NULL;
+                               table_size = 0;
+                       }
                }
  
                /* Update the variables to point into the current struct net
        }
        tbl[0].extra1 = net;
  
-       net->ipv4.route_hdr = register_net_sysctl(net, "net/ipv4/route", tbl);
+       net->ipv4.route_hdr = register_net_sysctl_sz(net, "net/ipv4/route",
+                                                    tbl, table_size);
        if (!net->ipv4.route_hdr)
                goto err_reg;
        return 0;
diff --combined net/ipv4/xfrm4_policy.c
index cdcc0f6b4f0a2909e5c66902b24dd99e80431eb1,57ea394ffa8c5694bec37428269e3ad2dd5fbec0..c33bca2c3841540b20e92efe4202b07646c3714c
@@@ -124,13 -124,22 +124,13 @@@ static void xfrm4_dst_destroy(struct ds
        xfrm_dst_destroy(xdst);
  }
  
 -static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
 -                           int unregister)
 -{
 -      if (!unregister)
 -              return;
 -
 -      xfrm_dst_ifdown(dst, dev);
 -}
 -
  static struct dst_ops xfrm4_dst_ops_template = {
        .family =               AF_INET,
        .update_pmtu =          xfrm4_update_pmtu,
        .redirect =             xfrm4_redirect,
        .cow_metrics =          dst_cow_metrics_generic,
        .destroy =              xfrm4_dst_destroy,
 -      .ifdown =               xfrm4_dst_ifdown,
 +      .ifdown =               xfrm_dst_ifdown,
        .local_out =            __ip_local_out,
        .gc_thresh =            32768,
  };
@@@ -169,7 -178,8 +169,8 @@@ static __net_init int xfrm4_net_sysctl_
                table[0].data = &net->xfrm.xfrm4_dst_ops.gc_thresh;
        }
  
-       hdr = register_net_sysctl(net, "net/ipv4", table);
+       hdr = register_net_sysctl_sz(net, "net/ipv4", table,
+                                    ARRAY_SIZE(xfrm4_policy_table));
        if (!hdr)
                goto err_reg;
  
diff --combined net/ipv6/addrconf.c
index 47d1dd8501b7471e2903fee3032612aa0b7d7da9,61291bd247b997b379e071b107f10882d37bcd6d..967913ad65e54ae3cd63925dbc5846bfb040c850
@@@ -202,7 -202,6 +202,7 @@@ static struct ipv6_devconf ipv6_devcon
        .ra_defrtr_metric       = IP6_RT_PRIO_USER,
        .accept_ra_from_local   = 0,
        .accept_ra_min_hop_limit= 1,
 +      .accept_ra_min_lft      = 0,
        .accept_ra_pinfo        = 1,
  #ifdef CONFIG_IPV6_ROUTER_PREF
        .accept_ra_rtr_pref     = 1,
@@@ -263,7 -262,6 +263,7 @@@ static struct ipv6_devconf ipv6_devconf
        .ra_defrtr_metric       = IP6_RT_PRIO_USER,
        .accept_ra_from_local   = 0,
        .accept_ra_min_hop_limit= 1,
 +      .accept_ra_min_lft      = 0,
        .accept_ra_pinfo        = 1,
  #ifdef CONFIG_IPV6_ROUTER_PREF
        .accept_ra_rtr_pref     = 1,
@@@ -320,8 -318,9 +320,8 @@@ static void addrconf_del_dad_work(struc
  static void addrconf_mod_rs_timer(struct inet6_dev *idev,
                                  unsigned long when)
  {
 -      if (!timer_pending(&idev->rs_timer))
 +      if (!mod_timer(&idev->rs_timer, jiffies + when))
                in6_dev_hold(idev);
 -      mod_timer(&idev->rs_timer, jiffies + when);
  }
  
  static void addrconf_mod_dad_work(struct inet6_ifaddr *ifp,
@@@ -1063,28 -1062,20 +1063,28 @@@ ipv6_add_addr(struct inet6_dev *idev, s
        struct fib6_info *f6i = NULL;
        int err = 0;
  
 -      if (addr_type == IPV6_ADDR_ANY ||
 -          (addr_type & IPV6_ADDR_MULTICAST &&
 -           !(cfg->ifa_flags & IFA_F_MCAUTOJOIN)) ||
 -          (!(idev->dev->flags & IFF_LOOPBACK) &&
 -           !netif_is_l3_master(idev->dev) &&
 -           addr_type & IPV6_ADDR_LOOPBACK))
 +      if (addr_type == IPV6_ADDR_ANY) {
 +              NL_SET_ERR_MSG_MOD(extack, "Invalid address");
                return ERR_PTR(-EADDRNOTAVAIL);
 +      } else if (addr_type & IPV6_ADDR_MULTICAST &&
 +                 !(cfg->ifa_flags & IFA_F_MCAUTOJOIN)) {
 +              NL_SET_ERR_MSG_MOD(extack, "Cannot assign multicast address without \"IFA_F_MCAUTOJOIN\" flag");
 +              return ERR_PTR(-EADDRNOTAVAIL);
 +      } else if (!(idev->dev->flags & IFF_LOOPBACK) &&
 +                 !netif_is_l3_master(idev->dev) &&
 +                 addr_type & IPV6_ADDR_LOOPBACK) {
 +              NL_SET_ERR_MSG_MOD(extack, "Cannot assign loopback address on this device");
 +              return ERR_PTR(-EADDRNOTAVAIL);
 +      }
  
        if (idev->dead) {
 -              err = -ENODEV;                  /*XXX*/
 +              NL_SET_ERR_MSG_MOD(extack, "device is going away");
 +              err = -ENODEV;
                goto out;
        }
  
        if (idev->cnf.disable_ipv6) {
 +              NL_SET_ERR_MSG_MOD(extack, "IPv6 is disabled on this device");
                err = -EACCES;
                goto out;
        }
                goto out;
        }
  
 -      f6i = addrconf_f6i_alloc(net, idev, cfg->pfx, false, gfp_flags);
 +      f6i = addrconf_f6i_alloc(net, idev, cfg->pfx, false, gfp_flags, extack);
        if (IS_ERR(f6i)) {
                err = PTR_ERR(f6i);
                f6i = NULL;
@@@ -2571,18 -2562,12 +2571,18 @@@ static void manage_tempaddrs(struct ine
                        ipv6_ifa_notify(0, ift);
        }
  
 -      if ((create || list_empty(&idev->tempaddr_list)) &&
 -          idev->cnf.use_tempaddr > 0) {
 +      /* Also create a temporary address if it's enabled but no temporary
 +       * address currently exists.
 +       * However, we get called with valid_lft == 0, prefered_lft == 0, create == false
 +       * as part of cleanup (ie. deleting the mngtmpaddr).
 +       * We don't want that to result in creating a new temporary ip address.
 +       */
 +      if (list_empty(&idev->tempaddr_list) && (valid_lft || prefered_lft))
 +              create = true;
 +
 +      if (create && idev->cnf.use_tempaddr > 0) {
                /* When a new public address is created as described
                 * in [ADDRCONF], also create a new temporary address.
 -               * Also create a temporary address if it's enabled but
 -               * no temporary address currently exists.
                 */
                read_unlock_bh(&idev->lock);
                ipv6_create_tempaddr(ifp, false);
@@@ -2741,9 -2726,6 +2741,9 @@@ void addrconf_prefix_rcv(struct net_dev
                return;
        }
  
 +      if (valid_lft != 0 && valid_lft < in6_dev->cnf.accept_ra_min_lft)
 +              goto put;
 +
        /*
         *      Two things going on here:
         *      1) Add routes for on-link prefixes
@@@ -2938,40 -2920,30 +2938,40 @@@ static int inet6_addr_add(struct net *n
  
        ASSERT_RTNL();
  
 -      if (cfg->plen > 128)
 +      if (cfg->plen > 128) {
 +              NL_SET_ERR_MSG_MOD(extack, "Invalid prefix length");
                return -EINVAL;
 +      }
  
        /* check the lifetime */
 -      if (!cfg->valid_lft || cfg->preferred_lft > cfg->valid_lft)
 +      if (!cfg->valid_lft || cfg->preferred_lft > cfg->valid_lft) {
 +              NL_SET_ERR_MSG_MOD(extack, "address lifetime invalid");
                return -EINVAL;
 +      }
  
 -      if (cfg->ifa_flags & IFA_F_MANAGETEMPADDR && cfg->plen != 64)
 +      if (cfg->ifa_flags & IFA_F_MANAGETEMPADDR && cfg->plen != 64) {
 +              NL_SET_ERR_MSG_MOD(extack, "address with \"mngtmpaddr\" flag must have a prefix length of 64");
                return -EINVAL;
 +      }
  
        dev = __dev_get_by_index(net, ifindex);
        if (!dev)
                return -ENODEV;
  
        idev = addrconf_add_dev(dev);
 -      if (IS_ERR(idev))
 +      if (IS_ERR(idev)) {
 +              NL_SET_ERR_MSG_MOD(extack, "IPv6 is disabled on this device");
                return PTR_ERR(idev);
 +      }
  
        if (cfg->ifa_flags & IFA_F_MCAUTOJOIN) {
                int ret = ipv6_mc_config(net->ipv6.mc_autojoin_sk,
                                         true, cfg->pfx, ifindex);
  
 -              if (ret < 0)
 +              if (ret < 0) {
 +                      NL_SET_ERR_MSG_MOD(extack, "Multicast auto join failed");
                        return ret;
 +              }
        }
  
        cfg->scope = ipv6_addr_scope(cfg->pfx);
  }
  
  static int inet6_addr_del(struct net *net, int ifindex, u32 ifa_flags,
 -                        const struct in6_addr *pfx, unsigned int plen)
 +                        const struct in6_addr *pfx, unsigned int plen,
 +                        struct netlink_ext_ack *extack)
  {
        struct inet6_ifaddr *ifp;
        struct inet6_dev *idev;
        struct net_device *dev;
  
 -      if (plen > 128)
 +      if (plen > 128) {
 +              NL_SET_ERR_MSG_MOD(extack, "Invalid prefix length");
                return -EINVAL;
 +      }
  
        dev = __dev_get_by_index(net, ifindex);
 -      if (!dev)
 +      if (!dev) {
 +              NL_SET_ERR_MSG_MOD(extack, "Unable to find the interface");
                return -ENODEV;
 +      }
  
        idev = __in6_dev_get(dev);
 -      if (!idev)
 +      if (!idev) {
 +              NL_SET_ERR_MSG_MOD(extack, "IPv6 is disabled on this device");
                return -ENXIO;
 +      }
  
        read_lock_bh(&idev->lock);
        list_for_each_entry(ifp, &idev->addr_list, if_list) {
                }
        }
        read_unlock_bh(&idev->lock);
 +
 +      NL_SET_ERR_MSG_MOD(extack, "address not found");
        return -EADDRNOTAVAIL;
  }
  
@@@ -3117,7 -3080,7 +3117,7 @@@ int addrconf_del_ifaddr(struct net *net
  
        rtnl_lock();
        err = inet6_addr_del(net, ireq.ifr6_ifindex, 0, &ireq.ifr6_addr,
 -                           ireq.ifr6_prefixlen);
 +                           ireq.ifr6_prefixlen, NULL);
        rtnl_unlock();
        return err;
  }
@@@ -3520,7 -3483,7 +3520,7 @@@ static int fixup_permanent_addr(struct 
                struct fib6_info *f6i, *prev;
  
                f6i = addrconf_f6i_alloc(net, idev, &ifp->addr, false,
 -                                       GFP_ATOMIC);
 +                                       GFP_ATOMIC, NULL);
                if (IS_ERR(f6i))
                        return PTR_ERR(f6i);
  
@@@ -4730,7 -4693,7 +4730,7 @@@ inet6_rtm_deladdr(struct sk_buff *skb, 
        ifa_flags &= IFA_F_MANAGETEMPADDR;
  
        return inet6_addr_del(net, ifm->ifa_index, ifa_flags, pfx,
 -                            ifm->ifa_prefixlen);
 +                            ifm->ifa_prefixlen, extack);
  }
  
  static int modify_prefix_route(struct inet6_ifaddr *ifp,
@@@ -4935,10 -4898,8 +4935,10 @@@ inet6_rtm_newaddr(struct sk_buff *skb, 
        }
  
        dev =  __dev_get_by_index(net, ifm->ifa_index);
 -      if (!dev)
 +      if (!dev) {
 +              NL_SET_ERR_MSG_MOD(extack, "Unable to find the interface");
                return -ENODEV;
 +      }
  
        if (tb[IFA_FLAGS])
                cfg.ifa_flags = nla_get_u32(tb[IFA_FLAGS]);
        }
  
        if (nlh->nlmsg_flags & NLM_F_EXCL ||
 -          !(nlh->nlmsg_flags & NLM_F_REPLACE))
 +          !(nlh->nlmsg_flags & NLM_F_REPLACE)) {
 +              NL_SET_ERR_MSG_MOD(extack, "address already assigned");
                err = -EEXIST;
 -      else
 +      } else {
                err = inet6_addr_modify(net, ifa, &cfg);
 +      }
  
        in6_ifa_put(ifa);
  
@@@ -5638,7 -5597,6 +5638,7 @@@ static inline void ipv6_store_devconf(s
        array[DEVCONF_IOAM6_ID_WIDE] = cnf->ioam6_id_wide;
        array[DEVCONF_NDISC_EVICT_NOCARRIER] = cnf->ndisc_evict_nocarrier;
        array[DEVCONF_ACCEPT_UNTRACKED_NA] = cnf->accept_untracked_na;
 +      array[DEVCONF_ACCEPT_RA_MIN_LFT] = cnf->accept_ra_min_lft;
  }
  
  static inline size_t inet6_ifla6_size(void)
@@@ -6832,13 -6790,6 +6832,13 @@@ static const struct ctl_table addrconf_
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
 +      {
 +              .procname       = "accept_ra_min_lft",
 +              .data           = &ipv6_devconf.accept_ra_min_lft,
 +              .maxlen         = sizeof(int),
 +              .mode           = 0644,
 +              .proc_handler   = proc_dointvec,
 +      },
        {
                .procname       = "accept_ra_pinfo",
                .data           = &ipv6_devconf.accept_ra_pinfo,
@@@ -7135,7 -7086,8 +7135,8 @@@ static int __addrconf_sysctl_register(s
  
        snprintf(path, sizeof(path), "net/ipv6/conf/%s", dev_name);
  
-       p->sysctl_header = register_net_sysctl(net, path, table);
+       p->sysctl_header = register_net_sysctl_sz(net, path, table,
+                                                 ARRAY_SIZE(addrconf_sysctl));
        if (!p->sysctl_header)
                goto free;
  
diff --combined net/ipv6/icmp.c
index 6d88f5248c1f3d8eefa6abe9df3eacda9c213a00,4159662fa214e6d0f16552ffb9f04f856b0b4707..93a594a901d12befb754e7035f56726273eead92
@@@ -424,10 -424,7 +424,10 @@@ static struct net_device *icmp6_dev(con
        if (unlikely(dev->ifindex == LOOPBACK_IFINDEX || netif_is_l3_master(skb->dev))) {
                const struct rt6_info *rt6 = skb_rt6_info(skb);
  
 -              if (rt6)
 +              /* The destination could be an external IP in Ext Hdr (SRv6, RPL, etc.),
 +               * and ip6_null_entry could be set to skb if no route is found.
 +               */
 +              if (rt6 && rt6->rt6i_idev)
                        dev = rt6->rt6i_idev->dev;
        }
  
@@@ -1034,9 -1031,11 +1034,9 @@@ drop_no_count
        return 0;
  }
  
 -void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
 -                    u8 type,
 +void icmpv6_flow_init(const struct sock *sk, struct flowi6 *fl6, u8 type,
                      const struct in6_addr *saddr,
 -                    const struct in6_addr *daddr,
 -                    int oif)
 +                    const struct in6_addr *daddr, int oif)
  {
        memset(fl6, 0, sizeof(*fl6));
        fl6->saddr = *saddr;
@@@ -1227,4 -1226,9 +1227,9 @@@ struct ctl_table * __net_init ipv6_icmp
        }
        return table;
  }
+ size_t ipv6_icmp_sysctl_table_size(void)
+ {
+       return ARRAY_SIZE(ipv6_icmp_table_template);
+ }
  #endif
diff --combined net/ipv6/route.c
index 846aec8e00933e9d87444b292d797dbf1a5375fa,15cade57f7c64a5797883a5a99d6e8d537ff00ba..d15a9e3aa24aedd386eb05498340400236870816
@@@ -90,7 -90,7 +90,7 @@@ unsigned int          ip6_mtu(const struct dst_
  static struct dst_entry *ip6_negative_advice(struct dst_entry *);
  static void           ip6_dst_destroy(struct dst_entry *);
  static void           ip6_dst_ifdown(struct dst_entry *,
 -                                     struct net_device *dev, int how);
 +                                     struct net_device *dev);
  static void            ip6_dst_gc(struct dst_ops *ops);
  
  static int            ip6_pkt_discard(struct sk_buff *skb);
@@@ -371,7 -371,8 +371,7 @@@ static void ip6_dst_destroy(struct dst_
        fib6_info_release(from);
  }
  
 -static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
 -                         int how)
 +static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
  {
        struct rt6_info *rt = (struct rt6_info *)dst;
        struct inet6_dev *idev = rt->rt6i_idev;
@@@ -2950,8 -2951,7 +2950,8 @@@ void ip6_sk_update_pmtu(struct sk_buff 
        if (!oif && skb->dev)
                oif = l3mdev_master_ifindex(skb->dev);
  
 -      ip6_update_pmtu(skb, sock_net(sk), mtu, oif, sk->sk_mark, sk->sk_uid);
 +      ip6_update_pmtu(skb, sock_net(sk), mtu, oif, READ_ONCE(sk->sk_mark),
 +                      sk->sk_uid);
  
        dst = __sk_dst_get(sk);
        if (!dst || !dst->obsolete ||
@@@ -3172,8 -3172,8 +3172,8 @@@ void ip6_redirect_no_header(struct sk_b
  
  void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
  {
 -      ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
 -                   sk->sk_uid);
 +      ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if,
 +                   READ_ONCE(sk->sk_mark), sk->sk_uid);
  }
  EXPORT_SYMBOL_GPL(ip6_sk_redirect);
  
@@@ -3760,10 -3760,10 +3760,10 @@@ static struct fib6_info *ip6_route_info
                rt->dst_nocount = true;
  
        if (cfg->fc_flags & RTF_EXPIRES)
 -              fib6_set_expires(rt, jiffies +
 -                              clock_t_to_jiffies(cfg->fc_expires));
 +              fib6_set_expires_locked(rt, jiffies +
 +                                      clock_t_to_jiffies(cfg->fc_expires));
        else
 -              fib6_clean_expires(rt);
 +              fib6_clean_expires_locked(rt);
  
        if (cfg->fc_protocol == RTPROT_UNSPEC)
                cfg->fc_protocol = RTPROT_BOOT;
@@@ -4543,8 -4543,7 +4543,8 @@@ static int ip6_pkt_prohibit_out(struct 
  struct fib6_info *addrconf_f6i_alloc(struct net *net,
                                     struct inet6_dev *idev,
                                     const struct in6_addr *addr,
 -                                   bool anycast, gfp_t gfp_flags)
 +                                   bool anycast, gfp_t gfp_flags,
 +                                   struct netlink_ext_ack *extack)
  {
        struct fib6_config cfg = {
                .fc_table = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL,
                cfg.fc_flags |= RTF_LOCAL;
        }
  
 -      f6i = ip6_route_info_create(&cfg, gfp_flags, NULL);
 +      f6i = ip6_route_info_create(&cfg, gfp_flags, extack);
        if (!IS_ERR(f6i)) {
                f6i->dst_nocount = true;
  
  
  /* remove deleted ip from prefsrc entries */
  struct arg_dev_net_ip {
 -      struct net_device *dev;
        struct net *net;
        struct in6_addr *addr;
  };
  
  static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg)
  {
 -      struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
        struct net *net = ((struct arg_dev_net_ip *)arg)->net;
        struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
  
        if (!rt->nh &&
 -          ((void *)rt->fib6_nh->fib_nh_dev == dev || !dev) &&
            rt != net->ipv6.fib6_null_entry &&
 -          ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr)) {
 +          ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr) &&
 +          !ipv6_chk_addr(net, addr, rt->fib6_nh->fib_nh_dev, 0)) {
                spin_lock_bh(&rt6_exception_lock);
                /* remove prefsrc entry */
                rt->fib6_prefsrc.plen = 0;
@@@ -4606,6 -4607,7 +4606,6 @@@ void rt6_remove_prefsrc(struct inet6_if
  {
        struct net *net = dev_net(ifp->idev->dev);
        struct arg_dev_net_ip adni = {
 -              .dev = ifp->idev->dev,
                .net = net,
                .addr = &ifp->addr,
        };
@@@ -6453,6 -6455,15 +6453,15 @@@ struct ctl_table * __net_init ipv6_rout
  
        return table;
  }
+ size_t ipv6_route_sysctl_table_size(struct net *net)
+ {
+       /* Don't export sysctls to unprivileged users */
+       if (net->user_ns != &init_user_ns)
+               return 1;
+       return ARRAY_SIZE(ipv6_route_table_template);
+ }
  #endif
  
  static int __net_init ip6_route_net_init(struct net *net)
diff --combined net/ipv6/xfrm6_policy.c
index 188224a76685dd53751e120ecf9fa67d066c22d6,8f931e46b4601a6d3feb11fc46717f74a4b0be09..41a680c76d2ea56ed4c6bdb7556005888e892e39
@@@ -124,10 -124,14 +124,10 @@@ static void xfrm6_dst_destroy(struct ds
        xfrm_dst_destroy(xdst);
  }
  
 -static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
 -                           int unregister)
 +static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
  {
        struct xfrm_dst *xdst;
  
 -      if (!unregister)
 -              return;
 -
        xdst = (struct xfrm_dst *)dst;
        if (xdst->u.rt6.rt6i_idev->dev == dev) {
                struct inet6_dev *loopback_idev =
@@@ -201,7 -205,8 +201,8 @@@ static int __net_init xfrm6_net_sysctl_
                table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh;
        }
  
-       hdr = register_net_sysctl(net, "net/ipv6", table);
+       hdr = register_net_sysctl_sz(net, "net/ipv6", table,
+                                    ARRAY_SIZE(xfrm6_policy_table));
        if (!hdr)
                goto err_reg;
  
diff --combined net/mptcp/ctrl.c
index c46c22a84d235bf693e74d3447ef9e12234ab267,43e540328a5252c296c0fca49d68466223344427..e72b518c5d0266f091b61703f371c846b24dae33
@@@ -32,7 -32,6 +32,7 @@@ struct mptcp_pernet 
        u8 checksum_enabled;
        u8 allow_join_initial_addr_port;
        u8 pm_type;
 +      char scheduler[MPTCP_SCHED_NAME_MAX];
  };
  
  static struct mptcp_pernet *mptcp_get_pernet(const struct net *net)
@@@ -70,11 -69,6 +70,11 @@@ int mptcp_get_pm_type(const struct net 
        return mptcp_get_pernet(net)->pm_type;
  }
  
 +const char *mptcp_get_scheduler(const struct net *net)
 +{
 +      return mptcp_get_pernet(net)->scheduler;
 +}
 +
  static void mptcp_pernet_set_defaults(struct mptcp_pernet *pernet)
  {
        pernet->mptcp_enabled = 1;
@@@ -83,7 -77,6 +83,7 @@@
        pernet->allow_join_initial_addr_port = 1;
        pernet->stale_loss_cnt = 4;
        pernet->pm_type = MPTCP_PM_TYPE_KERNEL;
 +      strcpy(pernet->scheduler, "default");
  }
  
  #ifdef CONFIG_SYSCTL
@@@ -135,12 -128,6 +135,12 @@@ static struct ctl_table mptcp_sysctl_ta
                .extra1       = SYSCTL_ZERO,
                .extra2       = &mptcp_pm_type_max
        },
 +      {
 +              .procname = "scheduler",
 +              .maxlen = MPTCP_SCHED_NAME_MAX,
 +              .mode = 0644,
 +              .proc_handler = proc_dostring,
 +      },
        {}
  };
  
@@@ -162,9 -149,9 +162,10 @@@ static int mptcp_pernet_new_table(struc
        table[3].data = &pernet->allow_join_initial_addr_port;
        table[4].data = &pernet->stale_loss_cnt;
        table[5].data = &pernet->pm_type;
 +      table[6].data = &pernet->scheduler;
  
-       hdr = register_net_sysctl(net, MPTCP_SYSCTL_PATH, table);
+       hdr = register_net_sysctl_sz(net, MPTCP_SYSCTL_PATH, table,
+                                    ARRAY_SIZE(mptcp_sysctl_table));
        if (!hdr)
                goto err_reg;
  
index 4bb0d90eca1cd67a8b83f7ccc1a63038b41aaefb,8d69e4c2d8222facbfe01888f5088f8678ccb400..143a341bbc0a4dbda5d802939fa52f54544096c5
@@@ -1876,7 -1876,6 +1876,7 @@@ static in
  proc_do_sync_threshold(struct ctl_table *table, int write,
                       void *buffer, size_t *lenp, loff_t *ppos)
  {
 +      struct netns_ipvs *ipvs = table->extra2;
        int *valp = table->data;
        int val[2];
        int rc;
                .mode = table->mode,
        };
  
 +      mutex_lock(&ipvs->sync_mutex);
        memcpy(val, valp, sizeof(val));
        rc = proc_dointvec(&tmp, write, buffer, lenp, ppos);
        if (write) {
                else
                        memcpy(valp, val, sizeof(val));
        }
 +      mutex_unlock(&ipvs->sync_mutex);
        return rc;
  }
  
@@@ -4269,6 -4266,7 +4269,7 @@@ static int __net_init ip_vs_control_net
        struct net *net = ipvs->net;
        struct ctl_table *tbl;
        int idx, ret;
+       size_t ctl_table_size = ARRAY_SIZE(vs_vars);
  
        atomic_set(&ipvs->dropentry, 0);
        spin_lock_init(&ipvs->dropentry_lock);
                        return -ENOMEM;
  
                /* Don't export sysctls to unprivileged users */
-               if (net->user_ns != &init_user_ns)
+               if (net->user_ns != &init_user_ns) {
                        tbl[0].procname = NULL;
+                       ctl_table_size = 0;
+               }
        } else
                tbl = vs_vars;
        /* Initialize sysctl defaults */
        ipvs->sysctl_sync_threshold[0] = DEFAULT_SYNC_THRESHOLD;
        ipvs->sysctl_sync_threshold[1] = DEFAULT_SYNC_PERIOD;
        tbl[idx].data = &ipvs->sysctl_sync_threshold;
 +      tbl[idx].extra2 = ipvs;
        tbl[idx++].maxlen = sizeof(ipvs->sysctl_sync_threshold);
        ipvs->sysctl_sync_refresh_period = DEFAULT_SYNC_REFRESH_PERIOD;
        tbl[idx++].data = &ipvs->sysctl_sync_refresh_period;
  #endif
  
        ret = -ENOMEM;
-       ipvs->sysctl_hdr = register_net_sysctl(net, "net/ipv4/vs", tbl);
+       ipvs->sysctl_hdr = register_net_sysctl_sz(net, "net/ipv4/vs", tbl,
+                                                 ctl_table_size);
        if (!ipvs->sysctl_hdr)
                goto err;
        ipvs->sysctl_tbl = tbl;
diff --combined net/smc/smc_sysctl.c
index 0b2a957ca5f5f09408cc94460fde5e53b5fa4b5d,3ab2d8eefc5560944f2ee69e51f083b416835853..5cbc18c6e62b07d09dc4b99a165287d6ccac4922
  
  static int min_sndbuf = SMC_BUF_MIN_SIZE;
  static int min_rcvbuf = SMC_BUF_MIN_SIZE;
 +static int max_sndbuf = INT_MAX / 2;
 +static int max_rcvbuf = INT_MAX / 2;
 +static const int net_smc_wmem_init = (64 * 1024);
 +static const int net_smc_rmem_init = (64 * 1024);
  
  static struct ctl_table smc_table[] = {
        {
@@@ -57,7 -53,6 +57,7 @@@
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
                .extra1         = &min_sndbuf,
 +              .extra2         = &max_sndbuf,
        },
        {
                .procname       = "rmem",
@@@ -66,7 -61,6 +66,7 @@@
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
                .extra1         = &min_rcvbuf,
 +              .extra2         = &max_rcvbuf,
        },
        {  }
  };
@@@ -87,15 -81,16 +87,16 @@@ int __net_init smc_sysctl_net_init(stru
                        table[i].data += (void *)net - (void *)&init_net;
        }
  
-       net->smc.smc_hdr = register_net_sysctl(net, "net/smc", table);
+       net->smc.smc_hdr = register_net_sysctl_sz(net, "net/smc", table,
+                                                 ARRAY_SIZE(smc_table));
        if (!net->smc.smc_hdr)
                goto err_reg;
  
        net->smc.sysctl_autocorking_size = SMC_AUTOCORKING_DEFAULT_SIZE;
        net->smc.sysctl_smcr_buf_type = SMCR_PHYS_CONT_BUFS;
        net->smc.sysctl_smcr_testlink_time = SMC_LLC_TESTLINK_DEFAULT_TIME;
 -      WRITE_ONCE(net->smc.sysctl_wmem, READ_ONCE(net->ipv4.sysctl_tcp_wmem[1]));
 -      WRITE_ONCE(net->smc.sysctl_rmem, READ_ONCE(net->ipv4.sysctl_tcp_rmem[1]));
 +      WRITE_ONCE(net->smc.sysctl_wmem, net_smc_wmem_init);
 +      WRITE_ONCE(net->smc.sysctl_rmem, net_smc_rmem_init);
  
        return 0;
  
This page took 0.193812 seconds and 4 git commands to generate.