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
proc_domemused(CONST_CTL_TABLE * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)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
proc_doslab(CONST_CTL_TABLE * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)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
proc_dohostid(CONST_CTL_TABLE * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)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
slab_seq_show_headers(struct seq_file * f)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
slab_seq_show(struct seq_file * f,void * p)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 *
slab_seq_start(struct seq_file * f,loff_t * pos)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 *
slab_seq_next(struct seq_file * f,void * p,loff_t * pos)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
slab_seq_stop(struct seq_file * f,void * v)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
proc_slab_open(struct inode * inode,struct file * filp)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
spl_proc_cleanup(void)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
spl_proc_init(void)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
spl_proc_fini(void)536eda14cbcSMatt Macy spl_proc_fini(void)
537eda14cbcSMatt Macy {
5382ad756a6SMartin Matuska spl_proc_cleanup();
539eda14cbcSMatt Macy }
540