1 /*****************************************************************************\
2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3 * Copyright (C) 2007 The Regents of the University of California.
4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5 * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://zfsonlinux.org/>.
11 * The SPL is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * You should have received a copy of the GNU General Public License along
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************
24 * Solaris Porting Layer (SPL) Proc Implementation.
25 \*****************************************************************************/
27 #include <sys/systeminfo.h>
28 #include <sys/kstat.h>
30 #include <sys/kmem_cache.h>
32 #include <linux/ctype.h>
33 #include <linux/kmod.h>
34 #include <linux/seq_file.h>
35 #include <linux/proc_compat.h>
36 #include <linux/uaccess.h>
37 #include <linux/version.h>
39 #if defined(CONSTIFY_PLUGIN) && LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
40 typedef struct ctl_table __no_const spl_ctl_table
;
42 typedef struct ctl_table spl_ctl_table
;
45 static unsigned long table_min
= 0;
46 static unsigned long table_max
= ~0;
48 static struct ctl_table_header
*spl_header
= NULL
;
49 static struct proc_dir_entry
*proc_spl
= NULL
;
50 static struct proc_dir_entry
*proc_spl_kmem
= NULL
;
51 static struct proc_dir_entry
*proc_spl_kmem_slab
= NULL
;
52 struct proc_dir_entry
*proc_spl_kstat
= NULL
;
55 proc_copyin_string(char *kbuffer
, int kbuffer_size
,
56 const char *ubuffer
, int ubuffer_size
)
60 if (ubuffer_size
> kbuffer_size
)
63 if (copy_from_user((void *)kbuffer
, (void *)ubuffer
, ubuffer_size
))
66 /* strip trailing whitespace */
67 size
= strnlen(kbuffer
, ubuffer_size
);
69 if (!isspace(kbuffer
[size
]))
76 /* no space to terminate */
77 if (size
== kbuffer_size
)
80 kbuffer
[size
+ 1] = 0;
85 proc_copyout_string(char *ubuffer
, int ubuffer_size
,
86 const char *kbuffer
, char *append
)
88 /* NB if 'append' != NULL, it's a single character to append to the
89 * copied out string - usually "\n", for /proc entries and
90 * (i.e. a terminating zero byte) for sysctl entries
92 int size
= MIN(strlen(kbuffer
), ubuffer_size
);
94 if (copy_to_user(ubuffer
, kbuffer
, size
))
97 if (append
!= NULL
&& size
< ubuffer_size
) {
98 if (copy_to_user(ubuffer
+ size
, append
, 1))
109 proc_domemused(struct ctl_table
*table
, int write
,
110 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
113 unsigned long min
= 0, max
= ~0, val
;
114 spl_ctl_table dummy
= *table
;
117 dummy
.proc_handler
= &proc_dointvec
;
124 # ifdef HAVE_ATOMIC64_T
125 val
= atomic64_read((atomic64_t
*)table
->data
);
127 val
= atomic_read((atomic_t
*)table
->data
);
128 # endif /* HAVE_ATOMIC64_T */
129 rc
= proc_doulongvec_minmax(&dummy
, write
, buffer
, lenp
, ppos
);
134 #endif /* DEBUG_KMEM */
137 proc_doslab(struct ctl_table
*table
, int write
,
138 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
141 unsigned long min
= 0, max
= ~0, val
= 0, mask
;
142 spl_ctl_table dummy
= *table
;
143 spl_kmem_cache_t
*skc
;
146 dummy
.proc_handler
= &proc_dointvec
;
153 down_read(&spl_kmem_cache_sem
);
154 mask
= (unsigned long)table
->data
;
156 list_for_each_entry(skc
, &spl_kmem_cache_list
, skc_list
) {
158 /* Only use slabs of the correct kmem/vmem type */
159 if (!(skc
->skc_flags
& mask
))
162 /* Sum the specified field for selected slabs */
163 switch (mask
& (KMC_TOTAL
| KMC_ALLOC
| KMC_MAX
)) {
165 val
+= skc
->skc_slab_size
* skc
->skc_slab_total
;
168 val
+= skc
->skc_obj_size
* skc
->skc_obj_alloc
;
171 val
+= skc
->skc_obj_size
* skc
->skc_obj_max
;
176 up_read(&spl_kmem_cache_sem
);
177 rc
= proc_doulongvec_minmax(&dummy
, write
, buffer
, lenp
, ppos
);
184 proc_dohostid(struct ctl_table
*table
, int write
,
185 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
191 /* We can't use proc_doulongvec_minmax() in the write
192 * case here because hostid while a hex value has no
193 * leading 0x which confuses the helper function. */
194 rc
= proc_copyin_string(str
, sizeof(str
), buffer
, *lenp
);
198 spl_hostid
= simple_strtoul(str
, &end
, 16);
203 len
= snprintf(str
, sizeof(str
), "%lx", spl_hostid
);
207 rc
= proc_copyout_string(buffer
,*lenp
,str
+*ppos
,"\n");
219 slab_seq_show_headers(struct seq_file
*f
)
222 "--------------------- cache ----------"
223 "--------------------------------------------- "
226 "--- emergency ---\n");
229 " flags size alloc slabsize objsize "
232 "dlock alloc max\n");
236 slab_seq_show(struct seq_file
*f
, void *p
)
238 spl_kmem_cache_t
*skc
= p
;
240 ASSERT(skc
->skc_magic
== SKC_MAGIC
);
243 * Backed by Linux slab see /proc/slabinfo.
245 if (skc
->skc_flags
& KMC_SLAB
)
248 spin_lock(&skc
->skc_lock
);
249 seq_printf(f
, "%-36s ", skc
->skc_name
);
250 seq_printf(f
, "0x%05lx %9lu %9lu %8u %8u "
251 "%5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n",
252 (long unsigned)skc
->skc_flags
,
253 (long unsigned)(skc
->skc_slab_size
* skc
->skc_slab_total
),
254 (long unsigned)(skc
->skc_obj_size
* skc
->skc_obj_alloc
),
255 (unsigned)skc
->skc_slab_size
,
256 (unsigned)skc
->skc_obj_size
,
257 (long unsigned)skc
->skc_slab_total
,
258 (long unsigned)skc
->skc_slab_alloc
,
259 (long unsigned)skc
->skc_slab_max
,
260 (long unsigned)skc
->skc_obj_total
,
261 (long unsigned)skc
->skc_obj_alloc
,
262 (long unsigned)skc
->skc_obj_max
,
263 (long unsigned)skc
->skc_obj_deadlock
,
264 (long unsigned)skc
->skc_obj_emergency
,
265 (long unsigned)skc
->skc_obj_emergency_max
);
267 spin_unlock(&skc
->skc_lock
);
273 slab_seq_start(struct seq_file
*f
, loff_t
*pos
)
278 down_read(&spl_kmem_cache_sem
);
280 slab_seq_show_headers(f
);
282 p
= spl_kmem_cache_list
.next
;
285 if (p
== &spl_kmem_cache_list
)
289 return (list_entry(p
, spl_kmem_cache_t
, skc_list
));
293 slab_seq_next(struct seq_file
*f
, void *p
, loff_t
*pos
)
295 spl_kmem_cache_t
*skc
= p
;
298 return ((skc
->skc_list
.next
== &spl_kmem_cache_list
) ?
299 NULL
: list_entry(skc
->skc_list
.next
,spl_kmem_cache_t
,skc_list
));
303 slab_seq_stop(struct seq_file
*f
, void *v
)
305 up_read(&spl_kmem_cache_sem
);
308 static struct seq_operations slab_seq_ops
= {
309 .show
= slab_seq_show
,
310 .start
= slab_seq_start
,
311 .next
= slab_seq_next
,
312 .stop
= slab_seq_stop
,
316 proc_slab_open(struct inode
*inode
, struct file
*filp
)
318 return seq_open(filp
, &slab_seq_ops
);
321 static struct file_operations proc_slab_operations
= {
322 .open
= proc_slab_open
,
325 .release
= seq_release
,
328 static struct ctl_table spl_kmem_table
[] = {
331 .procname
= "kmem_used",
332 .data
= &kmem_alloc_used
,
333 # ifdef HAVE_ATOMIC64_T
334 .maxlen
= sizeof(atomic64_t
),
336 .maxlen
= sizeof(atomic_t
),
337 # endif /* HAVE_ATOMIC64_T */
339 .proc_handler
= &proc_domemused
,
342 .procname
= "kmem_max",
343 .data
= &kmem_alloc_max
,
344 .maxlen
= sizeof(unsigned long),
345 .extra1
= &table_min
,
346 .extra2
= &table_max
,
348 .proc_handler
= &proc_doulongvec_minmax
,
350 #endif /* DEBUG_KMEM */
352 .procname
= "slab_kmem_total",
353 .data
= (void *)(KMC_KMEM
| KMC_TOTAL
),
354 .maxlen
= sizeof(unsigned long),
355 .extra1
= &table_min
,
356 .extra2
= &table_max
,
358 .proc_handler
= &proc_doslab
,
361 .procname
= "slab_kmem_alloc",
362 .data
= (void *)(KMC_KMEM
| KMC_ALLOC
),
363 .maxlen
= sizeof(unsigned long),
364 .extra1
= &table_min
,
365 .extra2
= &table_max
,
367 .proc_handler
= &proc_doslab
,
370 .procname
= "slab_kmem_max",
371 .data
= (void *)(KMC_KMEM
| KMC_MAX
),
372 .maxlen
= sizeof(unsigned long),
373 .extra1
= &table_min
,
374 .extra2
= &table_max
,
376 .proc_handler
= &proc_doslab
,
379 .procname
= "slab_vmem_total",
380 .data
= (void *)(KMC_VMEM
| KMC_TOTAL
),
381 .maxlen
= sizeof(unsigned long),
382 .extra1
= &table_min
,
383 .extra2
= &table_max
,
385 .proc_handler
= &proc_doslab
,
388 .procname
= "slab_vmem_alloc",
389 .data
= (void *)(KMC_VMEM
| KMC_ALLOC
),
390 .maxlen
= sizeof(unsigned long),
391 .extra1
= &table_min
,
392 .extra2
= &table_max
,
394 .proc_handler
= &proc_doslab
,
397 .procname
= "slab_vmem_max",
398 .data
= (void *)(KMC_VMEM
| KMC_MAX
),
399 .maxlen
= sizeof(unsigned long),
400 .extra1
= &table_min
,
401 .extra2
= &table_max
,
403 .proc_handler
= &proc_doslab
,
408 static struct ctl_table spl_kstat_table
[] = {
412 static struct ctl_table spl_table
[] = {
413 /* NB No .strategy entries have been provided since
414 * sysctl(8) prefers to go via /proc for portability.
417 .procname
= "version",
419 .maxlen
= sizeof(spl_version
),
421 .proc_handler
= &proc_dostring
,
424 .procname
= "hostid",
426 .maxlen
= sizeof(unsigned long),
428 .proc_handler
= &proc_dohostid
,
433 .child
= spl_kmem_table
,
438 .child
= spl_kstat_table
,
443 static struct ctl_table spl_dir
[] = {
452 static struct ctl_table spl_root
[] = {
455 .ctl_name
= CTL_KERN
,
457 .procname
= "kernel",
469 spl_header
= register_sysctl_table(spl_root
);
470 if (spl_header
== NULL
)
473 proc_spl
= proc_mkdir("spl", NULL
);
474 if (proc_spl
== NULL
) {
479 proc_spl_kmem
= proc_mkdir("kmem", proc_spl
);
480 if (proc_spl_kmem
== NULL
) {
485 proc_spl_kmem_slab
= proc_create_data("slab", 0444,
486 proc_spl_kmem
, &proc_slab_operations
, NULL
);
487 if (proc_spl_kmem_slab
== NULL
) {
492 proc_spl_kstat
= proc_mkdir("kstat", proc_spl
);
493 if (proc_spl_kstat
== NULL
) {
499 remove_proc_entry("kstat", proc_spl
);
500 remove_proc_entry("slab", proc_spl_kmem
);
501 remove_proc_entry("kmem", proc_spl
);
502 remove_proc_entry("spl", NULL
);
503 unregister_sysctl_table(spl_header
);
512 remove_proc_entry("kstat", proc_spl
);
513 remove_proc_entry("slab", proc_spl_kmem
);
514 remove_proc_entry("kmem", proc_spl
);
515 remove_proc_entry("spl", NULL
);
517 ASSERT(spl_header
!= NULL
);
518 unregister_sysctl_table(spl_header
);