Merge tag 'sysctl-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 27 Apr 2023 23:52:33 +0000 (16:52 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 27 Apr 2023 23:52:33 +0000 (16:52 -0700)
Pull sysctl updates from Luis Chamberlain:
 "This only does a few sysctl moves from the kernel/sysctl.c file, the
  rest of the work has been put towards deprecating two API calls which
  incur recursion and prevent us from simplifying the registration
  process / saving memory per move. Most of the changes have been
  soaking on linux-next since v6.3-rc3.

  I've slowed down the kernel/sysctl.c moves due to Matthew Wilcox's
  feedback that we should see if we could *save* memory with these moves
  instead of incurring more memory. We currently incur more memory since
  when we move a syctl from kernel/sysclt.c out to its own file we end
  up having to add a new empty sysctl used to register it. To achieve
  saving memory we want to allow syctls to be passed without requiring
  the end element being empty, and just have our registration process
  rely on ARRAY_SIZE(). Without this, supporting both styles of sysctls
  would make the sysctl registration pretty brittle, hard to read and
  maintain as can be seen from Meng Tang's efforts to do just this [0].
  Fortunately, in order to use ARRAY_SIZE() for all sysctl registrations
  also implies doing the work to deprecate two API calls which use
  recursion in order to support sysctl declarations with subdirectories.

  And so during this development cycle quite a bit of effort went into
  this deprecation effort. I've annotated the following two APIs are
  deprecated and in few kernel releases we should be good to remove
  them:

   - register_sysctl_table()
   - register_sysctl_paths()

  During this merge window we should be able to deprecate and unexport
  register_sysctl_paths(), we can probably do that towards the end of
  this merge window.

  Deprecating register_sysctl_table() will take a bit more time but this
  pull request goes with a few example of how to do this.

  As it turns out each of the conversions to move away from either of
  these two API calls *also* saves memory. And so long term, all these
  changes *will* prove to have saved a bit of memory on boot.

  The way I see it then is if remove a user of one deprecated call, it
  gives us enough savings to move one kernel/sysctl.c out from the
  generic arrays as we end up with about the same amount of bytes.

  Since deprecating register_sysctl_table() and register_sysctl_paths()
  does not require maintainer coordination except the final unexport
  you'll see quite a bit of these changes from other pull requests, I've
  just kept the stragglers after rc3"

Link: https://lkml.kernel.org/r/ZAD+cpbrqlc5vmry@bombadil.infradead.org
* tag 'sysctl-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux: (29 commits)
  fs: fix sysctls.c built
  mm: compaction: remove incorrect #ifdef checks
  mm: compaction: move compaction sysctl to its own file
  mm: memory-failure: Move memory failure sysctls to its own file
  arm: simplify two-level sysctl registration for ctl_isa_vars
  ia64: simplify one-level sysctl registration for kdump_ctl_table
  utsname: simplify one-level sysctl registration for uts_kern_table
  ntfs: simplfy one-level sysctl registration for ntfs_sysctls
  coda: simplify one-level sysctl registration for coda_table
  fs/cachefiles: simplify one-level sysctl registration for cachefiles_sysctls
  xfs: simplify two-level sysctl registration for xfs_table
  nfs: simplify two-level sysctl registration for nfs_cb_sysctls
  nfs: simplify two-level sysctl registration for nfs4_cb_sysctls
  lockd: simplify two-level sysctl registration for nlm_sysctls
  proc_sysctl: enhance documentation
  xen: simplify sysctl registration for balloon
  md: simplify sysctl registration
  hv: simplify sysctl registration
  scsi: simplify sysctl registration with register_sysctl()
  csky: simplify alignment sysctl registration
  ...

1  2 
drivers/hv/vmbus_drv.c
drivers/md/md.c
fs/userfaultfd.c
mm/hugetlb.c
security/apparmor/lsm.c
security/loadpin/loadpin.c
security/yama/yama_lsm.c

diff --combined drivers/hv/vmbus_drv.c
@@@ -684,7 -684,7 +684,7 @@@ static const struct attribute_group vmb
  __ATTRIBUTE_GROUPS(vmbus_dev);
  
  /* Set up the attribute for /sys/bus/vmbus/hibernation */
 -static ssize_t hibernation_show(struct bus_type *bus, char *buf)
 +static ssize_t hibernation_show(const struct bus_type *bus, char *buf)
  {
        return sprintf(buf, "%d\n", !!hv_is_hibernation_supported());
  }
@@@ -1460,15 -1460,6 +1460,6 @@@ static struct ctl_table hv_ctl_table[] 
        {}
  };
  
- static struct ctl_table hv_root_table[] = {
-       {
-               .procname       = "kernel",
-               .mode           = 0555,
-               .child          = hv_ctl_table
-       },
-       {}
- };
  /*
   * vmbus_bus_init -Main vmbus driver initialization routine.
   *
@@@ -1547,7 -1538,7 +1538,7 @@@ static int vmbus_bus_init(void
                 * message recording won't be available in isolated
                 * guests should the following registration fail.
                 */
-               hv_ctl_table_hdr = register_sysctl_table(hv_root_table);
+               hv_ctl_table_hdr = register_sysctl("kernel", hv_ctl_table);
                if (!hv_ctl_table_hdr)
                        pr_err("Hyper-V: sysctl table register error");
  
@@@ -2156,6 -2147,7 +2147,6 @@@ void vmbus_device_unregister(struct hv_
   * VMBUS is an acpi enumerated device. Get the information we
   * need from DSDT.
   */
 -#define VTPM_BASE_ADDRESS 0xfed40000
  static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
  {
        resource_size_t start = 0;
diff --combined drivers/md/md.c
@@@ -78,7 -78,7 +78,7 @@@
  static LIST_HEAD(pers_list);
  static DEFINE_SPINLOCK(pers_lock);
  
 -static struct kobj_type md_ktype;
 +static const struct kobj_type md_ktype;
  
  struct md_cluster_operations *md_cluster_ops;
  EXPORT_SYMBOL(md_cluster_ops);
@@@ -322,26 -322,6 +322,6 @@@ static struct ctl_table raid_table[] = 
        { }
  };
  
- static struct ctl_table raid_dir_table[] = {
-       {
-               .procname       = "raid",
-               .maxlen         = 0,
-               .mode           = S_IRUGO|S_IXUGO,
-               .child          = raid_table,
-       },
-       { }
- };
- static struct ctl_table raid_root_table[] = {
-       {
-               .procname       = "dev",
-               .maxlen         = 0,
-               .mode           = 0555,
-               .child          = raid_dir_table,
-       },
-       {  }
- };
  static int start_readonly;
  
  /*
@@@ -3600,7 -3580,7 +3580,7 @@@ static const struct sysfs_ops rdev_sysf
        .show           = rdev_attr_show,
        .store          = rdev_attr_store,
  };
 -static struct kobj_type rdev_ktype = {
 +static const struct kobj_type rdev_ktype = {
        .release        = rdev_free,
        .sysfs_ops      = &rdev_sysfs_ops,
        .default_groups = rdev_default_groups,
@@@ -5558,7 -5538,7 +5538,7 @@@ static const struct sysfs_ops md_sysfs_
        .show   = md_attr_show,
        .store  = md_attr_store,
  };
 -static struct kobj_type md_ktype = {
 +static const struct kobj_type md_ktype = {
        .release        = md_kobj_release,
        .sysfs_ops      = &md_sysfs_ops,
        .default_groups = md_attr_groups,
@@@ -6260,6 -6240,7 +6240,6 @@@ static void __md_stop(struct mddev *mdd
        module_put(pers->owner);
        clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
  
 -      percpu_ref_exit(&mddev->writes_pending);
        percpu_ref_exit(&mddev->active_io);
        bioset_exit(&mddev->bio_set);
        bioset_exit(&mddev->sync_set);
@@@ -6272,7 -6253,6 +6252,7 @@@ void md_stop(struct mddev *mddev
         */
        __md_stop_writes(mddev);
        __md_stop(mddev);
 +      percpu_ref_exit(&mddev->writes_pending);
  }
  
  EXPORT_SYMBOL_GPL(md_stop);
@@@ -7843,7 -7823,6 +7823,7 @@@ static void md_free_disk(struct gendis
  {
        struct mddev *mddev = disk->private_data;
  
 +      percpu_ref_exit(&mddev->writes_pending);
        mddev_free(mddev);
  }
  
@@@ -7974,9 -7953,6 +7954,9 @@@ void md_error(struct mddev *mddev, stru
                return;
        mddev->pers->error_handler(mddev, rdev);
  
 +      if (mddev->pers->level == 0 || mddev->pers->level == LEVEL_LINEAR)
 +              return;
 +
        if (mddev->degraded && !test_bit(MD_BROKEN, &mddev->flags))
                set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
        sysfs_notify_dirent_safe(rdev->sysfs_state);
@@@ -8032,16 -8008,16 +8012,16 @@@ static int status_resync(struct seq_fil
        } else if (resync > max_sectors) {
                resync = max_sectors;
        } else {
 -              resync -= atomic_read(&mddev->recovery_active);
 -              if (resync < MD_RESYNC_ACTIVE) {
 -                      /*
 -                       * Resync has started, but the subtraction has
 -                       * yielded one of the special values. Force it
 -                       * to active to ensure the status reports an
 -                       * active resync.
 -                       */
 +              res = atomic_read(&mddev->recovery_active);
 +              /*
 +               * Resync has started, but the subtraction has overflowed or
 +               * yielded one of the special values. Force it to active to
 +               * ensure the status reports an active resync.
 +               */
 +              if (resync < res || resync - res < MD_RESYNC_ACTIVE)
                        resync = MD_RESYNC_ACTIVE;
 -              }
 +              else
 +                      resync -= res;
        }
  
        if (resync == MD_RESYNC_NONE) {
@@@ -9653,7 -9629,7 +9633,7 @@@ static int __init md_init(void
        mdp_major = ret;
  
        register_reboot_notifier(&md_notifier);
-       raid_table_header = register_sysctl_table(raid_root_table);
+       raid_table_header = register_sysctl("dev/raid", raid_table);
  
        md_geninit();
        return 0;
diff --combined fs/userfaultfd.c
  #include <linux/swapops.h>
  #include <linux/miscdevice.h>
  
- int sysctl_unprivileged_userfaultfd __read_mostly;
+ static int sysctl_unprivileged_userfaultfd __read_mostly;
+ #ifdef CONFIG_SYSCTL
+ static struct ctl_table vm_userfaultfd_table[] = {
+       {
+               .procname       = "unprivileged_userfaultfd",
+               .data           = &sysctl_unprivileged_userfaultfd,
+               .maxlen         = sizeof(sysctl_unprivileged_userfaultfd),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
+       },
+       { }
+ };
+ #endif
  
  static struct kmem_cache *userfaultfd_ctx_cachep __read_mostly;
  
@@@ -1955,10 -1970,8 +1970,10 @@@ static int userfaultfd_api(struct userf
        ret = -EFAULT;
        if (copy_from_user(&uffdio_api, buf, sizeof(uffdio_api)))
                goto out;
 -      /* Ignore unsupported features (userspace built against newer kernel) */
 -      features = uffdio_api.features & UFFD_API_FEATURES;
 +      features = uffdio_api.features;
 +      ret = -EINVAL;
 +      if (uffdio_api.api != UFFD_API || (features & ~UFFD_API_FEATURES))
 +              goto err_out;
        ret = -EPERM;
        if ((features & UFFD_FEATURE_EVENT_FORK) && !capable(CAP_SYS_PTRACE))
                goto err_out;
@@@ -2180,6 -2193,9 +2195,9 @@@ static int __init userfaultfd_init(void
                                                0,
                                                SLAB_HWCACHE_ALIGN|SLAB_PANIC,
                                                init_once_userfaultfd_ctx);
+ #ifdef CONFIG_SYSCTL
+       register_sysctl_init("vm", vm_userfaultfd_table);
+ #endif
        return 0;
  }
  __initcall(userfaultfd_init);
diff --combined mm/hugetlb.c
@@@ -4202,6 -4202,12 +4202,12 @@@ static void __init hugetlb_sysfs_init(v
        hugetlb_register_all_nodes();
  }
  
+ #ifdef CONFIG_SYSCTL
+ static void hugetlb_sysctl_init(void);
+ #else
+ static inline void hugetlb_sysctl_init(void) { }
+ #endif
  static int __init hugetlb_init(void)
  {
        int i;
  
        hugetlb_sysfs_init();
        hugetlb_cgroup_file_init();
+       hugetlb_sysctl_init();
  
  #ifdef CONFIG_SMP
        num_fault_mutexes = roundup_pow_of_two(8 * num_possible_cpus());
@@@ -4588,7 -4595,7 +4595,7 @@@ out
        return ret;
  }
  
- int hugetlb_sysctl_handler(struct ctl_table *table, int write,
static int hugetlb_sysctl_handler(struct ctl_table *table, int write,
                          void *buffer, size_t *length, loff_t *ppos)
  {
  
  }
  
  #ifdef CONFIG_NUMA
- int hugetlb_mempolicy_sysctl_handler(struct ctl_table *table, int write,
static int hugetlb_mempolicy_sysctl_handler(struct ctl_table *table, int write,
                          void *buffer, size_t *length, loff_t *ppos)
  {
        return hugetlb_sysctl_handler_common(true, table, write,
  }
  #endif /* CONFIG_NUMA */
  
- int hugetlb_overcommit_handler(struct ctl_table *table, int write,
static int hugetlb_overcommit_handler(struct ctl_table *table, int write,
                void *buffer, size_t *length, loff_t *ppos)
  {
        struct hstate *h = &default_hstate;
        return ret;
  }
  
+ static struct ctl_table hugetlb_table[] = {
+       {
+               .procname       = "nr_hugepages",
+               .data           = NULL,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = hugetlb_sysctl_handler,
+       },
+ #ifdef CONFIG_NUMA
+       {
+               .procname       = "nr_hugepages_mempolicy",
+               .data           = NULL,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &hugetlb_mempolicy_sysctl_handler,
+       },
+ #endif
+       {
+               .procname       = "hugetlb_shm_group",
+               .data           = &sysctl_hugetlb_shm_group,
+               .maxlen         = sizeof(gid_t),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .procname       = "nr_overcommit_hugepages",
+               .data           = NULL,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = hugetlb_overcommit_handler,
+       },
+       { }
+ };
+ static void hugetlb_sysctl_init(void)
+ {
+       register_sysctl_init("vm", hugetlb_table);
+ }
  #endif /* CONFIG_SYSCTL */
  
  void hugetlb_report_meminfo(struct seq_file *m)
@@@ -5478,7 -5523,7 +5523,7 @@@ static vm_fault_t hugetlb_wp(struct mm_
                       struct folio *pagecache_folio, spinlock_t *ptl)
  {
        const bool unshare = flags & FAULT_FLAG_UNSHARE;
 -      pte_t pte;
 +      pte_t pte = huge_ptep_get(ptep);
        struct hstate *h = hstate_vma(vma);
        struct page *old_page;
        struct folio *new_folio;
        unsigned long haddr = address & huge_page_mask(h);
        struct mmu_notifier_range range;
  
 +      /*
 +       * Never handle CoW for uffd-wp protected pages.  It should be only
 +       * handled when the uffd-wp protection is removed.
 +       *
 +       * Note that only the CoW optimization path (in hugetlb_no_page())
 +       * can trigger this, because hugetlb_fault() will always resolve
 +       * uffd-wp bit first.
 +       */
 +      if (!unshare && huge_pte_uffd_wp(pte))
 +              return 0;
 +
        /*
         * hugetlb does not support FOLL_FORCE-style write faults that keep the
         * PTE mapped R/O such as maybe_mkwrite() would do.
                return 0;
        }
  
 -      pte = huge_ptep_get(ptep);
        old_page = pte_page(pte);
  
        delayacct_wpcopy_start();
diff --combined security/apparmor/lsm.c
@@@ -1209,13 -1209,13 +1209,13 @@@ static int apparmor_inet_conn_request(c
  /*
   * The cred blob is a pointer to, not an instance of, an aa_label.
   */
 -struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = {
 +struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = {
        .lbs_cred = sizeof(struct aa_label *),
        .lbs_file = sizeof(struct aa_file_ctx),
        .lbs_task = sizeof(struct aa_task_ctx),
  };
  
 -static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
 +static struct security_hook_list apparmor_hooks[] __ro_after_init = {
        LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
        LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
        LSM_HOOK_INIT(capget, apparmor_capget),
@@@ -1427,7 -1427,7 +1427,7 @@@ static const struct kernel_param_ops pa
        .get = param_get_aaintbool
  };
  /* Boot time disable flag */
 -static int apparmor_enabled __lsm_ro_after_init = 1;
 +static int apparmor_enabled __ro_after_init = 1;
  module_param_named(enabled, apparmor_enabled, aaintbool, 0444);
  
  static int __init apparmor_enabled_setup(char *str)
@@@ -1764,11 -1764,6 +1764,6 @@@ static int apparmor_dointvec(struct ctl
        return proc_dointvec(table, write, buffer, lenp, ppos);
  }
  
- static struct ctl_path apparmor_sysctl_path[] = {
-       { .procname = "kernel", },
-       { }
- };
  static struct ctl_table apparmor_sysctl_table[] = {
        {
                .procname       = "unprivileged_userns_apparmor_policy",
  
  static int __init apparmor_init_sysctl(void)
  {
-       return register_sysctl_paths(apparmor_sysctl_path,
-                                    apparmor_sysctl_table) ? 0 : -ENOMEM;
+       return register_sysctl("kernel", apparmor_sysctl_table) ? 0 : -ENOMEM;
  }
  #else
  static inline int apparmor_init_sysctl(void)
@@@ -52,12 -52,6 +52,6 @@@ static bool deny_reading_verity_digests
  #endif
  
  #ifdef CONFIG_SYSCTL
- static struct ctl_path loadpin_sysctl_path[] = {
-       { .procname = "kernel", },
-       { .procname = "loadpin", },
-       { }
- };
  static struct ctl_table loadpin_sysctl_table[] = {
        {
                .procname       = "enforce",
@@@ -214,7 -208,7 +208,7 @@@ static int loadpin_load_data(enum kerne
        return loadpin_check(NULL, (enum kernel_read_file_id) id);
  }
  
 -static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = {
 +static struct security_hook_list loadpin_hooks[] __ro_after_init = {
        LSM_HOOK_INIT(sb_free_security, loadpin_sb_free_security),
        LSM_HOOK_INIT(kernel_read_file, loadpin_read_file),
        LSM_HOOK_INIT(kernel_load_data, loadpin_load_data),
@@@ -262,7 -256,7 +256,7 @@@ static int __init loadpin_init(void
                enforce ? "" : "not ");
        parse_exclude();
  #ifdef CONFIG_SYSCTL
-       if (!register_sysctl_paths(loadpin_sysctl_path, loadpin_sysctl_table))
+       if (!register_sysctl("kernel/loadpin", loadpin_sysctl_table))
                pr_notice("sysctl registration failed!\n");
  #endif
        security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
diff --combined security/yama/yama_lsm.c
@@@ -421,7 -421,7 +421,7 @@@ static int yama_ptrace_traceme(struct t
        return rc;
  }
  
 -static struct security_hook_list yama_hooks[] __lsm_ro_after_init = {
 +static struct security_hook_list yama_hooks[] __ro_after_init = {
        LSM_HOOK_INIT(ptrace_access_check, yama_ptrace_access_check),
        LSM_HOOK_INIT(ptrace_traceme, yama_ptrace_traceme),
        LSM_HOOK_INIT(task_prctl, yama_task_prctl),
@@@ -447,12 -447,6 +447,6 @@@ static int yama_dointvec_minmax(struct 
  
  static int max_scope = YAMA_SCOPE_NO_ATTACH;
  
- static struct ctl_path yama_sysctl_path[] = {
-       { .procname = "kernel", },
-       { .procname = "yama", },
-       { }
- };
  static struct ctl_table yama_sysctl_table[] = {
        {
                .procname       = "ptrace_scope",
  };
  static void __init yama_init_sysctl(void)
  {
-       if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table))
+       if (!register_sysctl("kernel/yama", yama_sysctl_table))
                panic("Yama: sysctl registration failed.\n");
  }
  #else