1eda14cbcSMatt Macy /* 2eda14cbcSMatt Macy * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC. 3eda14cbcSMatt Macy * Copyright (C) 2007 The Regents of the University of California. 4eda14cbcSMatt Macy * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). 5eda14cbcSMatt Macy * Written by Brian Behlendorf <behlendorf1@llnl.gov>. 6eda14cbcSMatt Macy * UCRL-CODE-235197 7eda14cbcSMatt Macy * 8eda14cbcSMatt Macy * This file is part of the SPL, Solaris Porting Layer. 9eda14cbcSMatt Macy * 10eda14cbcSMatt Macy * The SPL is free software; you can redistribute it and/or modify it 11eda14cbcSMatt Macy * under the terms of the GNU General Public License as published by the 12eda14cbcSMatt Macy * Free Software Foundation; either version 2 of the License, or (at your 13eda14cbcSMatt Macy * option) any later version. 14eda14cbcSMatt Macy * 15eda14cbcSMatt Macy * The SPL is distributed in the hope that it will be useful, but WITHOUT 16eda14cbcSMatt Macy * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17eda14cbcSMatt Macy * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18eda14cbcSMatt Macy * for more details. 19eda14cbcSMatt Macy * 20eda14cbcSMatt Macy * You should have received a copy of the GNU General Public License along 21eda14cbcSMatt Macy * with the SPL. If not, see <http://www.gnu.org/licenses/>. 22eda14cbcSMatt Macy * 23eda14cbcSMatt Macy * Solaris Porting Layer (SPL) Proc Implementation. 24eda14cbcSMatt Macy */ 2529dc9349SMartin Matuska /* 2629dc9349SMartin Matuska * Copyright (c) 2024, Rob Norris <robn@despairlabs.com> 2729dc9349SMartin Matuska */ 28eda14cbcSMatt Macy 29eda14cbcSMatt Macy #include <sys/systeminfo.h> 30eda14cbcSMatt Macy #include <sys/kstat.h> 31eda14cbcSMatt Macy #include <sys/kmem.h> 32eda14cbcSMatt Macy #include <sys/kmem_cache.h> 33eda14cbcSMatt Macy #include <sys/vmem.h> 34eda14cbcSMatt Macy #include <sys/proc.h> 35eda14cbcSMatt Macy #include <linux/ctype.h> 36eda14cbcSMatt Macy #include <linux/kmod.h> 37eda14cbcSMatt Macy #include <linux/seq_file.h> 38eda14cbcSMatt Macy #include <linux/uaccess.h> 39eda14cbcSMatt Macy #include <linux/version.h> 40e92ffd9bSMartin Matuska #include "zfs_gitrev.h" 41eda14cbcSMatt Macy 42*7a7741afSMartin Matuska #if defined(CONSTIFY_PLUGIN) 43eda14cbcSMatt Macy typedef struct ctl_table __no_const spl_ctl_table; 44eda14cbcSMatt Macy #else 45eda14cbcSMatt Macy typedef struct ctl_table spl_ctl_table; 46eda14cbcSMatt Macy #endif 47eda14cbcSMatt Macy 4829dc9349SMartin Matuska #ifdef HAVE_PROC_HANDLER_CTL_TABLE_CONST 4929dc9349SMartin Matuska #define CONST_CTL_TABLE const struct ctl_table 5029dc9349SMartin Matuska #else 5129dc9349SMartin Matuska #define CONST_CTL_TABLE struct ctl_table 5229dc9349SMartin Matuska #endif 5329dc9349SMartin Matuska 54eda14cbcSMatt Macy static unsigned long table_min = 0; 55eda14cbcSMatt Macy static unsigned long table_max = ~0; 56eda14cbcSMatt Macy 57eda14cbcSMatt Macy static struct ctl_table_header *spl_header = NULL; 583159b89bSMartin Matuska #ifndef HAVE_REGISTER_SYSCTL_TABLE 593159b89bSMartin Matuska static struct ctl_table_header *spl_kmem = NULL; 603159b89bSMartin Matuska static struct ctl_table_header *spl_kstat = NULL; 613159b89bSMartin Matuska #endif 62eda14cbcSMatt Macy static struct proc_dir_entry *proc_spl = NULL; 63eda14cbcSMatt Macy static struct proc_dir_entry *proc_spl_kmem = NULL; 64eda14cbcSMatt Macy static struct proc_dir_entry *proc_spl_kmem_slab = NULL; 65eda14cbcSMatt Macy struct proc_dir_entry *proc_spl_kstat = NULL; 66eda14cbcSMatt Macy 67eda14cbcSMatt Macy #ifdef DEBUG_KMEM 68eda14cbcSMatt Macy static int 6929dc9349SMartin Matuska proc_domemused(CONST_CTL_TABLE *table, int write, 70eda14cbcSMatt Macy void __user *buffer, size_t *lenp, loff_t *ppos) 71eda14cbcSMatt Macy { 72eda14cbcSMatt Macy int rc = 0; 7316038816SMartin Matuska unsigned long val; 74eda14cbcSMatt Macy spl_ctl_table dummy = *table; 75eda14cbcSMatt Macy 76eda14cbcSMatt Macy dummy.data = &val; 77eda14cbcSMatt Macy dummy.proc_handler = &proc_dointvec; 7816038816SMartin Matuska dummy.extra1 = &table_min; 7916038816SMartin Matuska dummy.extra2 = &table_max; 80eda14cbcSMatt Macy 81eda14cbcSMatt Macy if (write) { 82eda14cbcSMatt Macy *ppos += *lenp; 83eda14cbcSMatt Macy } else { 84eda14cbcSMatt Macy #ifdef HAVE_ATOMIC64_T 85eda14cbcSMatt Macy val = atomic64_read((atomic64_t *)table->data); 86eda14cbcSMatt Macy #else 87eda14cbcSMatt Macy val = atomic_read((atomic_t *)table->data); 88eda14cbcSMatt Macy #endif /* HAVE_ATOMIC64_T */ 89eda14cbcSMatt Macy rc = proc_doulongvec_minmax(&dummy, write, buffer, lenp, ppos); 90eda14cbcSMatt Macy } 91eda14cbcSMatt Macy 92eda14cbcSMatt Macy return (rc); 93eda14cbcSMatt Macy } 94eda14cbcSMatt Macy #endif /* DEBUG_KMEM */ 95eda14cbcSMatt Macy 96eda14cbcSMatt Macy static int 9729dc9349SMartin Matuska proc_doslab(CONST_CTL_TABLE *table, int write, 98eda14cbcSMatt Macy void __user *buffer, size_t *lenp, loff_t *ppos) 99eda14cbcSMatt Macy { 100eda14cbcSMatt Macy int rc = 0; 10116038816SMartin Matuska unsigned long val = 0, mask; 102eda14cbcSMatt Macy spl_ctl_table dummy = *table; 103eda14cbcSMatt Macy spl_kmem_cache_t *skc = NULL; 104eda14cbcSMatt Macy 105eda14cbcSMatt Macy dummy.data = &val; 106eda14cbcSMatt Macy dummy.proc_handler = &proc_dointvec; 10716038816SMartin Matuska dummy.extra1 = &table_min; 10816038816SMartin Matuska dummy.extra2 = &table_max; 109eda14cbcSMatt Macy 110eda14cbcSMatt Macy if (write) { 111eda14cbcSMatt Macy *ppos += *lenp; 112eda14cbcSMatt Macy } else { 113eda14cbcSMatt Macy down_read(&spl_kmem_cache_sem); 114eda14cbcSMatt Macy mask = (unsigned long)table->data; 115eda14cbcSMatt Macy 116eda14cbcSMatt Macy list_for_each_entry(skc, &spl_kmem_cache_list, skc_list) { 117eda14cbcSMatt Macy 118eda14cbcSMatt Macy /* Only use slabs of the correct kmem/vmem type */ 119eda14cbcSMatt Macy if (!(skc->skc_flags & mask)) 120eda14cbcSMatt Macy continue; 121eda14cbcSMatt Macy 122eda14cbcSMatt Macy /* Sum the specified field for selected slabs */ 123eda14cbcSMatt Macy switch (mask & (KMC_TOTAL | KMC_ALLOC | KMC_MAX)) { 124eda14cbcSMatt Macy case KMC_TOTAL: 125eda14cbcSMatt Macy val += skc->skc_slab_size * skc->skc_slab_total; 126eda14cbcSMatt Macy break; 127eda14cbcSMatt Macy case KMC_ALLOC: 128eda14cbcSMatt Macy val += skc->skc_obj_size * skc->skc_obj_alloc; 129eda14cbcSMatt Macy break; 130eda14cbcSMatt Macy case KMC_MAX: 131eda14cbcSMatt Macy val += skc->skc_obj_size * skc->skc_obj_max; 132eda14cbcSMatt Macy break; 133eda14cbcSMatt Macy } 134eda14cbcSMatt Macy } 135eda14cbcSMatt Macy 136eda14cbcSMatt Macy up_read(&spl_kmem_cache_sem); 137eda14cbcSMatt Macy rc = proc_doulongvec_minmax(&dummy, write, buffer, lenp, ppos); 138eda14cbcSMatt Macy } 139eda14cbcSMatt Macy 140eda14cbcSMatt Macy return (rc); 141eda14cbcSMatt Macy } 142eda14cbcSMatt Macy 143eda14cbcSMatt Macy static int 14429dc9349SMartin Matuska proc_dohostid(CONST_CTL_TABLE *table, int write, 145eda14cbcSMatt Macy void __user *buffer, size_t *lenp, loff_t *ppos) 146eda14cbcSMatt Macy { 147eda14cbcSMatt Macy char *end, str[32]; 14816038816SMartin Matuska unsigned long hid; 14916038816SMartin Matuska spl_ctl_table dummy = *table; 15016038816SMartin Matuska 15116038816SMartin Matuska dummy.data = str; 15216038816SMartin Matuska dummy.maxlen = sizeof (str) - 1; 15316038816SMartin Matuska 15416038816SMartin Matuska if (!write) 15516038816SMartin Matuska snprintf(str, sizeof (str), "%lx", 15616038816SMartin Matuska (unsigned long) zone_get_hostid(NULL)); 15716038816SMartin Matuska 15816038816SMartin Matuska /* always returns 0 */ 15916038816SMartin Matuska proc_dostring(&dummy, write, buffer, lenp, ppos); 160eda14cbcSMatt Macy 161eda14cbcSMatt Macy if (write) { 162eda14cbcSMatt Macy /* 163eda14cbcSMatt Macy * We can't use proc_doulongvec_minmax() in the write 16416038816SMartin Matuska * case here because hostid, while a hex value, has no 16516038816SMartin Matuska * leading 0x, which confuses the helper function. 166eda14cbcSMatt Macy */ 167eda14cbcSMatt Macy 16816038816SMartin Matuska hid = simple_strtoul(str, &end, 16); 169eda14cbcSMatt Macy if (str == end) 170eda14cbcSMatt Macy return (-EINVAL); 17116038816SMartin Matuska spl_hostid = hid; 172eda14cbcSMatt Macy } 173eda14cbcSMatt Macy 17416038816SMartin Matuska return (0); 175eda14cbcSMatt Macy } 176eda14cbcSMatt Macy 177eda14cbcSMatt Macy static void 178eda14cbcSMatt Macy slab_seq_show_headers(struct seq_file *f) 179eda14cbcSMatt Macy { 180eda14cbcSMatt Macy seq_printf(f, 181eda14cbcSMatt Macy "--------------------- cache ----------" 182eda14cbcSMatt Macy "--------------------------------------------- " 183eda14cbcSMatt Macy "----- slab ------ " 184eda14cbcSMatt Macy "---- object ----- " 185eda14cbcSMatt Macy "--- emergency ---\n"); 186eda14cbcSMatt Macy seq_printf(f, 187eda14cbcSMatt Macy "name " 188eda14cbcSMatt Macy " flags size alloc slabsize objsize " 189eda14cbcSMatt Macy "total alloc max " 190eda14cbcSMatt Macy "total alloc max " 191eda14cbcSMatt Macy "dlock alloc max\n"); 192eda14cbcSMatt Macy } 193eda14cbcSMatt Macy 194eda14cbcSMatt Macy static int 195eda14cbcSMatt Macy slab_seq_show(struct seq_file *f, void *p) 196eda14cbcSMatt Macy { 197eda14cbcSMatt Macy spl_kmem_cache_t *skc = p; 198eda14cbcSMatt Macy 199eda14cbcSMatt Macy ASSERT(skc->skc_magic == SKC_MAGIC); 200eda14cbcSMatt Macy 201eda14cbcSMatt Macy if (skc->skc_flags & KMC_SLAB) { 202eda14cbcSMatt Macy /* 203eda14cbcSMatt Macy * This cache is backed by a generic Linux kmem cache which 204eda14cbcSMatt Macy * has its own accounting. For these caches we only track 205eda14cbcSMatt Macy * the number of active allocated objects that exist within 206eda14cbcSMatt Macy * the underlying Linux slabs. For the overall statistics of 207eda14cbcSMatt Macy * the underlying Linux cache please refer to /proc/slabinfo. 208eda14cbcSMatt Macy */ 209eda14cbcSMatt Macy spin_lock(&skc->skc_lock); 210eda14cbcSMatt Macy uint64_t objs_allocated = 211eda14cbcSMatt Macy percpu_counter_sum(&skc->skc_linux_alloc); 212eda14cbcSMatt Macy seq_printf(f, "%-36s ", skc->skc_name); 213eda14cbcSMatt Macy seq_printf(f, "0x%05lx %9s %9lu %8s %8u " 214eda14cbcSMatt Macy "%5s %5s %5s %5s %5lu %5s %5s %5s %5s\n", 215eda14cbcSMatt Macy (long unsigned)skc->skc_flags, 216eda14cbcSMatt Macy "-", 217eda14cbcSMatt Macy (long unsigned)(skc->skc_obj_size * objs_allocated), 218eda14cbcSMatt Macy "-", 219eda14cbcSMatt Macy (unsigned)skc->skc_obj_size, 220eda14cbcSMatt Macy "-", "-", "-", "-", 221eda14cbcSMatt Macy (long unsigned)objs_allocated, 222eda14cbcSMatt Macy "-", "-", "-", "-"); 223eda14cbcSMatt Macy spin_unlock(&skc->skc_lock); 224eda14cbcSMatt Macy return (0); 225eda14cbcSMatt Macy } 226eda14cbcSMatt Macy 227eda14cbcSMatt Macy spin_lock(&skc->skc_lock); 228eda14cbcSMatt Macy seq_printf(f, "%-36s ", skc->skc_name); 229eda14cbcSMatt Macy seq_printf(f, "0x%05lx %9lu %9lu %8u %8u " 230eda14cbcSMatt Macy "%5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n", 231eda14cbcSMatt Macy (long unsigned)skc->skc_flags, 232eda14cbcSMatt Macy (long unsigned)(skc->skc_slab_size * skc->skc_slab_total), 233eda14cbcSMatt Macy (long unsigned)(skc->skc_obj_size * skc->skc_obj_alloc), 234eda14cbcSMatt Macy (unsigned)skc->skc_slab_size, 235eda14cbcSMatt Macy (unsigned)skc->skc_obj_size, 236eda14cbcSMatt Macy (long unsigned)skc->skc_slab_total, 237eda14cbcSMatt Macy (long unsigned)skc->skc_slab_alloc, 238eda14cbcSMatt Macy (long unsigned)skc->skc_slab_max, 239eda14cbcSMatt Macy (long unsigned)skc->skc_obj_total, 240eda14cbcSMatt Macy (long unsigned)skc->skc_obj_alloc, 241eda14cbcSMatt Macy (long unsigned)skc->skc_obj_max, 242eda14cbcSMatt Macy (long unsigned)skc->skc_obj_deadlock, 243eda14cbcSMatt Macy (long unsigned)skc->skc_obj_emergency, 244eda14cbcSMatt Macy (long unsigned)skc->skc_obj_emergency_max); 245eda14cbcSMatt Macy spin_unlock(&skc->skc_lock); 246eda14cbcSMatt Macy return (0); 247eda14cbcSMatt Macy } 248eda14cbcSMatt Macy 249eda14cbcSMatt Macy static void * 250eda14cbcSMatt Macy slab_seq_start(struct seq_file *f, loff_t *pos) 251eda14cbcSMatt Macy { 252eda14cbcSMatt Macy struct list_head *p; 253eda14cbcSMatt Macy loff_t n = *pos; 254eda14cbcSMatt Macy 255eda14cbcSMatt Macy down_read(&spl_kmem_cache_sem); 256eda14cbcSMatt Macy if (!n) 257eda14cbcSMatt Macy slab_seq_show_headers(f); 258eda14cbcSMatt Macy 259eda14cbcSMatt Macy p = spl_kmem_cache_list.next; 260eda14cbcSMatt Macy while (n--) { 261eda14cbcSMatt Macy p = p->next; 262eda14cbcSMatt Macy if (p == &spl_kmem_cache_list) 263eda14cbcSMatt Macy return (NULL); 264eda14cbcSMatt Macy } 265eda14cbcSMatt Macy 266eda14cbcSMatt Macy return (list_entry(p, spl_kmem_cache_t, skc_list)); 267eda14cbcSMatt Macy } 268eda14cbcSMatt Macy 269eda14cbcSMatt Macy static void * 270eda14cbcSMatt Macy slab_seq_next(struct seq_file *f, void *p, loff_t *pos) 271eda14cbcSMatt Macy { 272eda14cbcSMatt Macy spl_kmem_cache_t *skc = p; 273eda14cbcSMatt Macy 274eda14cbcSMatt Macy ++*pos; 275eda14cbcSMatt Macy return ((skc->skc_list.next == &spl_kmem_cache_list) ? 276eda14cbcSMatt Macy NULL : list_entry(skc->skc_list.next, spl_kmem_cache_t, skc_list)); 277eda14cbcSMatt Macy } 278eda14cbcSMatt Macy 279eda14cbcSMatt Macy static void 280eda14cbcSMatt Macy slab_seq_stop(struct seq_file *f, void *v) 281eda14cbcSMatt Macy { 282eda14cbcSMatt Macy up_read(&spl_kmem_cache_sem); 283eda14cbcSMatt Macy } 284eda14cbcSMatt Macy 285e92ffd9bSMartin Matuska static const struct seq_operations slab_seq_ops = { 286eda14cbcSMatt Macy .show = slab_seq_show, 287eda14cbcSMatt Macy .start = slab_seq_start, 288eda14cbcSMatt Macy .next = slab_seq_next, 289eda14cbcSMatt Macy .stop = slab_seq_stop, 290eda14cbcSMatt Macy }; 291eda14cbcSMatt Macy 292eda14cbcSMatt Macy static int 293eda14cbcSMatt Macy proc_slab_open(struct inode *inode, struct file *filp) 294eda14cbcSMatt Macy { 295eda14cbcSMatt Macy return (seq_open(filp, &slab_seq_ops)); 296eda14cbcSMatt Macy } 297eda14cbcSMatt Macy 298eda14cbcSMatt Macy static const kstat_proc_op_t proc_slab_operations = { 299eda14cbcSMatt Macy #ifdef HAVE_PROC_OPS_STRUCT 300eda14cbcSMatt Macy .proc_open = proc_slab_open, 301eda14cbcSMatt Macy .proc_read = seq_read, 302eda14cbcSMatt Macy .proc_lseek = seq_lseek, 303eda14cbcSMatt Macy .proc_release = seq_release, 304eda14cbcSMatt Macy #else 305eda14cbcSMatt Macy .open = proc_slab_open, 306eda14cbcSMatt Macy .read = seq_read, 307eda14cbcSMatt Macy .llseek = seq_lseek, 308eda14cbcSMatt Macy .release = seq_release, 309eda14cbcSMatt Macy #endif 310eda14cbcSMatt Macy }; 311eda14cbcSMatt Macy 312eda14cbcSMatt Macy static struct ctl_table spl_kmem_table[] = { 313eda14cbcSMatt Macy #ifdef DEBUG_KMEM 314eda14cbcSMatt Macy { 315eda14cbcSMatt Macy .procname = "kmem_used", 316eda14cbcSMatt Macy .data = &kmem_alloc_used, 317eda14cbcSMatt Macy #ifdef HAVE_ATOMIC64_T 318eda14cbcSMatt Macy .maxlen = sizeof (atomic64_t), 319eda14cbcSMatt Macy #else 320eda14cbcSMatt Macy .maxlen = sizeof (atomic_t), 321eda14cbcSMatt Macy #endif /* HAVE_ATOMIC64_T */ 322eda14cbcSMatt Macy .mode = 0444, 323eda14cbcSMatt Macy .proc_handler = &proc_domemused, 324eda14cbcSMatt Macy }, 325eda14cbcSMatt Macy { 326eda14cbcSMatt Macy .procname = "kmem_max", 327eda14cbcSMatt Macy .data = &kmem_alloc_max, 328eda14cbcSMatt Macy .maxlen = sizeof (unsigned long), 329eda14cbcSMatt Macy .extra1 = &table_min, 330eda14cbcSMatt Macy .extra2 = &table_max, 331eda14cbcSMatt Macy .mode = 0444, 332eda14cbcSMatt Macy .proc_handler = &proc_doulongvec_minmax, 333eda14cbcSMatt Macy }, 334eda14cbcSMatt Macy #endif /* DEBUG_KMEM */ 335eda14cbcSMatt Macy { 336eda14cbcSMatt Macy .procname = "slab_kvmem_total", 337eda14cbcSMatt Macy .data = (void *)(KMC_KVMEM | KMC_TOTAL), 338eda14cbcSMatt Macy .maxlen = sizeof (unsigned long), 339eda14cbcSMatt Macy .extra1 = &table_min, 340eda14cbcSMatt Macy .extra2 = &table_max, 341eda14cbcSMatt Macy .mode = 0444, 342eda14cbcSMatt Macy .proc_handler = &proc_doslab, 343eda14cbcSMatt Macy }, 344eda14cbcSMatt Macy { 345eda14cbcSMatt Macy .procname = "slab_kvmem_alloc", 346eda14cbcSMatt Macy .data = (void *)(KMC_KVMEM | KMC_ALLOC), 347eda14cbcSMatt Macy .maxlen = sizeof (unsigned long), 348eda14cbcSMatt Macy .extra1 = &table_min, 349eda14cbcSMatt Macy .extra2 = &table_max, 350eda14cbcSMatt Macy .mode = 0444, 351eda14cbcSMatt Macy .proc_handler = &proc_doslab, 352eda14cbcSMatt Macy }, 353eda14cbcSMatt Macy { 354eda14cbcSMatt Macy .procname = "slab_kvmem_max", 355eda14cbcSMatt Macy .data = (void *)(KMC_KVMEM | KMC_MAX), 356eda14cbcSMatt Macy .maxlen = sizeof (unsigned long), 357eda14cbcSMatt Macy .extra1 = &table_min, 358eda14cbcSMatt Macy .extra2 = &table_max, 359eda14cbcSMatt Macy .mode = 0444, 360eda14cbcSMatt Macy .proc_handler = &proc_doslab, 361eda14cbcSMatt Macy }, 362eda14cbcSMatt Macy {}, 363eda14cbcSMatt Macy }; 364eda14cbcSMatt Macy 365eda14cbcSMatt Macy static struct ctl_table spl_kstat_table[] = { 366eda14cbcSMatt Macy {}, 367eda14cbcSMatt Macy }; 368eda14cbcSMatt Macy 369eda14cbcSMatt Macy static struct ctl_table spl_table[] = { 370eda14cbcSMatt Macy /* 371eda14cbcSMatt Macy * NB No .strategy entries have been provided since 372eda14cbcSMatt Macy * sysctl(8) prefers to go via /proc for portability. 373eda14cbcSMatt Macy */ 374eda14cbcSMatt Macy { 375eda14cbcSMatt Macy .procname = "gitrev", 376e92ffd9bSMartin Matuska .data = (char *)ZFS_META_GITREV, 377e92ffd9bSMartin Matuska .maxlen = sizeof (ZFS_META_GITREV), 378eda14cbcSMatt Macy .mode = 0444, 379eda14cbcSMatt Macy .proc_handler = &proc_dostring, 380eda14cbcSMatt Macy }, 381eda14cbcSMatt Macy { 382eda14cbcSMatt Macy .procname = "hostid", 383eda14cbcSMatt Macy .data = &spl_hostid, 384eda14cbcSMatt Macy .maxlen = sizeof (unsigned long), 385eda14cbcSMatt Macy .mode = 0644, 386eda14cbcSMatt Macy .proc_handler = &proc_dohostid, 387eda14cbcSMatt Macy }, 388315ee00fSMartin Matuska #ifdef HAVE_REGISTER_SYSCTL_TABLE 389eda14cbcSMatt Macy { 390eda14cbcSMatt Macy .procname = "kmem", 391eda14cbcSMatt Macy .mode = 0555, 392eda14cbcSMatt Macy .child = spl_kmem_table, 393eda14cbcSMatt Macy }, 394eda14cbcSMatt Macy { 395eda14cbcSMatt Macy .procname = "kstat", 396eda14cbcSMatt Macy .mode = 0555, 397eda14cbcSMatt Macy .child = spl_kstat_table, 398eda14cbcSMatt Macy }, 399315ee00fSMartin Matuska #endif 400eda14cbcSMatt Macy {}, 401eda14cbcSMatt Macy }; 402eda14cbcSMatt Macy 403315ee00fSMartin Matuska #ifdef HAVE_REGISTER_SYSCTL_TABLE 404eda14cbcSMatt Macy static struct ctl_table spl_dir[] = { 405eda14cbcSMatt Macy { 406eda14cbcSMatt Macy .procname = "spl", 407eda14cbcSMatt Macy .mode = 0555, 408eda14cbcSMatt Macy .child = spl_table, 409eda14cbcSMatt Macy }, 410eda14cbcSMatt Macy {} 411eda14cbcSMatt Macy }; 412eda14cbcSMatt Macy 413eda14cbcSMatt Macy static struct ctl_table spl_root[] = { 414eda14cbcSMatt Macy { 415eda14cbcSMatt Macy .procname = "kernel", 416eda14cbcSMatt Macy .mode = 0555, 417eda14cbcSMatt Macy .child = spl_dir, 418eda14cbcSMatt Macy }, 419eda14cbcSMatt Macy {} 420eda14cbcSMatt Macy }; 421315ee00fSMartin Matuska #endif 422eda14cbcSMatt Macy 4232ad756a6SMartin Matuska static void spl_proc_cleanup(void) 4242ad756a6SMartin Matuska { 4252ad756a6SMartin Matuska remove_proc_entry("kstat", proc_spl); 4262ad756a6SMartin Matuska remove_proc_entry("slab", proc_spl_kmem); 4272ad756a6SMartin Matuska remove_proc_entry("kmem", proc_spl); 4282ad756a6SMartin Matuska remove_proc_entry("spl", NULL); 4292ad756a6SMartin Matuska 4303159b89bSMartin Matuska #ifndef HAVE_REGISTER_SYSCTL_TABLE 4313159b89bSMartin Matuska if (spl_kstat) { 4323159b89bSMartin Matuska unregister_sysctl_table(spl_kstat); 4333159b89bSMartin Matuska spl_kstat = NULL; 4343159b89bSMartin Matuska } 4353159b89bSMartin Matuska if (spl_kmem) { 4363159b89bSMartin Matuska unregister_sysctl_table(spl_kmem); 4373159b89bSMartin Matuska spl_kmem = NULL; 4383159b89bSMartin Matuska } 4393159b89bSMartin Matuska #endif 4402ad756a6SMartin Matuska if (spl_header) { 4412ad756a6SMartin Matuska unregister_sysctl_table(spl_header); 4422ad756a6SMartin Matuska spl_header = NULL; 4432ad756a6SMartin Matuska } 4442ad756a6SMartin Matuska } 4452ad756a6SMartin Matuska 44629dc9349SMartin Matuska #ifndef HAVE_REGISTER_SYSCTL_TABLE 44729dc9349SMartin Matuska 44829dc9349SMartin Matuska /* 44929dc9349SMartin Matuska * Traditionally, struct ctl_table arrays have been terminated by an "empty" 45029dc9349SMartin Matuska * sentinel element (specifically, one with .procname == NULL). 45129dc9349SMartin Matuska * 45229dc9349SMartin Matuska * Linux 6.6 began migrating away from this, adding register_sysctl_sz() so 45329dc9349SMartin Matuska * that callers could provide the size directly, and redefining 45429dc9349SMartin Matuska * register_sysctl() to just call register_sysctl_sz() with the array size. It 45529dc9349SMartin Matuska * retained support for the terminating element so that existing callers would 45629dc9349SMartin Matuska * continue to work. 45729dc9349SMartin Matuska * 45829dc9349SMartin Matuska * Linux 6.11 removed support for the terminating element, instead interpreting 45929dc9349SMartin Matuska * it as a real malformed element, and rejecting it. 46029dc9349SMartin Matuska * 46129dc9349SMartin Matuska * In order to continue support older kernels, we retain the terminating 46229dc9349SMartin Matuska * sentinel element for our sysctl tables, but instead detect availability of 46329dc9349SMartin Matuska * register_sysctl_sz(). If it exists, we pass it the array size -1, stopping 46429dc9349SMartin Matuska * the kernel from trying to process the terminator. For pre-6.6 kernels that 46529dc9349SMartin Matuska * don't have register_sysctl_sz(), we just use register_sysctl(), which can 46629dc9349SMartin Matuska * handle the terminating element as it always has. 46729dc9349SMartin Matuska */ 46829dc9349SMartin Matuska #ifdef HAVE_REGISTER_SYSCTL_SZ 46929dc9349SMartin Matuska #define spl_proc_register_sysctl(p, t) \ 47029dc9349SMartin Matuska register_sysctl_sz(p, t, ARRAY_SIZE(t)-1) 47129dc9349SMartin Matuska #else 47229dc9349SMartin Matuska #define spl_proc_register_sysctl(p, t) \ 47329dc9349SMartin Matuska register_sysctl(p, t) 47429dc9349SMartin Matuska #endif 47529dc9349SMartin Matuska #endif 47629dc9349SMartin Matuska 477eda14cbcSMatt Macy int 478eda14cbcSMatt Macy spl_proc_init(void) 479eda14cbcSMatt Macy { 480eda14cbcSMatt Macy int rc = 0; 481eda14cbcSMatt Macy 482315ee00fSMartin Matuska #ifdef HAVE_REGISTER_SYSCTL_TABLE 483eda14cbcSMatt Macy spl_header = register_sysctl_table(spl_root); 484eda14cbcSMatt Macy if (spl_header == NULL) 485eda14cbcSMatt Macy return (-EUNATCH); 486315ee00fSMartin Matuska #else 48729dc9349SMartin Matuska spl_header = spl_proc_register_sysctl("kernel/spl", spl_table); 488315ee00fSMartin Matuska if (spl_header == NULL) 489315ee00fSMartin Matuska return (-EUNATCH); 490315ee00fSMartin Matuska 49129dc9349SMartin Matuska spl_kmem = spl_proc_register_sysctl("kernel/spl/kmem", spl_kmem_table); 4923159b89bSMartin Matuska if (spl_kmem == NULL) { 493315ee00fSMartin Matuska rc = -EUNATCH; 494315ee00fSMartin Matuska goto out; 495315ee00fSMartin Matuska } 49629dc9349SMartin Matuska spl_kstat = spl_proc_register_sysctl("kernel/spl/kstat", 49729dc9349SMartin Matuska spl_kstat_table); 4983159b89bSMartin Matuska if (spl_kstat == NULL) { 499315ee00fSMartin Matuska rc = -EUNATCH; 500315ee00fSMartin Matuska goto out; 501315ee00fSMartin Matuska } 502315ee00fSMartin Matuska #endif 503eda14cbcSMatt Macy 504eda14cbcSMatt Macy proc_spl = proc_mkdir("spl", NULL); 505eda14cbcSMatt Macy if (proc_spl == NULL) { 506eda14cbcSMatt Macy rc = -EUNATCH; 507eda14cbcSMatt Macy goto out; 508eda14cbcSMatt Macy } 509eda14cbcSMatt Macy 510eda14cbcSMatt Macy proc_spl_kmem = proc_mkdir("kmem", proc_spl); 511eda14cbcSMatt Macy if (proc_spl_kmem == NULL) { 512eda14cbcSMatt Macy rc = -EUNATCH; 513eda14cbcSMatt Macy goto out; 514eda14cbcSMatt Macy } 515eda14cbcSMatt Macy 516eda14cbcSMatt Macy proc_spl_kmem_slab = proc_create_data("slab", 0444, proc_spl_kmem, 517eda14cbcSMatt Macy &proc_slab_operations, NULL); 518eda14cbcSMatt Macy if (proc_spl_kmem_slab == NULL) { 519eda14cbcSMatt Macy rc = -EUNATCH; 520eda14cbcSMatt Macy goto out; 521eda14cbcSMatt Macy } 522eda14cbcSMatt Macy 523eda14cbcSMatt Macy proc_spl_kstat = proc_mkdir("kstat", proc_spl); 524eda14cbcSMatt Macy if (proc_spl_kstat == NULL) { 525eda14cbcSMatt Macy rc = -EUNATCH; 526eda14cbcSMatt Macy goto out; 527eda14cbcSMatt Macy } 528eda14cbcSMatt Macy out: 5292ad756a6SMartin Matuska if (rc) 5302ad756a6SMartin Matuska spl_proc_cleanup(); 531eda14cbcSMatt Macy 532eda14cbcSMatt Macy return (rc); 533eda14cbcSMatt Macy } 534eda14cbcSMatt Macy 535eda14cbcSMatt Macy void 536eda14cbcSMatt Macy spl_proc_fini(void) 537eda14cbcSMatt Macy { 5382ad756a6SMartin Matuska spl_proc_cleanup(); 539eda14cbcSMatt Macy } 540