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
;
46 static unsigned long table_min
= 0;
47 static unsigned long table_max
= ~0;
50 static struct ctl_table_header
*spl_header
= NULL
;
51 static struct proc_dir_entry
*proc_spl
= NULL
;
53 static struct proc_dir_entry
*proc_spl_kmem
= NULL
;
54 static struct proc_dir_entry
*proc_spl_kmem_slab
= NULL
;
55 #endif /* DEBUG_KMEM */
56 struct proc_dir_entry
*proc_spl_kstat
= NULL
;
59 proc_copyin_string(char *kbuffer
, int kbuffer_size
,
60 const char *ubuffer
, int ubuffer_size
)
64 if (ubuffer_size
> kbuffer_size
)
67 if (copy_from_user((void *)kbuffer
, (void *)ubuffer
, ubuffer_size
))
70 /* strip trailing whitespace */
71 size
= strnlen(kbuffer
, ubuffer_size
);
73 if (!isspace(kbuffer
[size
]))
80 /* no space to terminate */
81 if (size
== kbuffer_size
)
84 kbuffer
[size
+ 1] = 0;
89 proc_copyout_string(char *ubuffer
, int ubuffer_size
,
90 const char *kbuffer
, char *append
)
92 /* NB if 'append' != NULL, it's a single character to append to the
93 * copied out string - usually "\n", for /proc entries and
94 * (i.e. a terminating zero byte) for sysctl entries
96 int size
= MIN(strlen(kbuffer
), ubuffer_size
);
98 if (copy_to_user(ubuffer
, kbuffer
, size
))
101 if (append
!= NULL
&& size
< ubuffer_size
) {
102 if (copy_to_user(ubuffer
+ size
, append
, 1))
113 proc_domemused(struct ctl_table
*table
, int write
,
114 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
117 unsigned long min
= 0, max
= ~0, val
;
118 spl_ctl_table dummy
= *table
;
121 dummy
.proc_handler
= &proc_dointvec
;
128 # ifdef HAVE_ATOMIC64_T
129 val
= atomic64_read((atomic64_t
*)table
->data
);
131 val
= atomic_read((atomic_t
*)table
->data
);
132 # endif /* HAVE_ATOMIC64_T */
133 rc
= proc_doulongvec_minmax(&dummy
, write
, buffer
, lenp
, ppos
);
140 proc_doslab(struct ctl_table
*table
, int write
,
141 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
144 unsigned long min
= 0, max
= ~0, val
= 0, mask
;
145 spl_ctl_table dummy
= *table
;
146 spl_kmem_cache_t
*skc
;
149 dummy
.proc_handler
= &proc_dointvec
;
156 down_read(&spl_kmem_cache_sem
);
157 mask
= (unsigned long)table
->data
;
159 list_for_each_entry(skc
, &spl_kmem_cache_list
, skc_list
) {
161 /* Only use slabs of the correct kmem/vmem type */
162 if (!(skc
->skc_flags
& mask
))
165 /* Sum the specified field for selected slabs */
166 switch (mask
& (KMC_TOTAL
| KMC_ALLOC
| KMC_MAX
)) {
168 val
+= skc
->skc_slab_size
* skc
->skc_slab_total
;
171 val
+= skc
->skc_obj_size
* skc
->skc_obj_alloc
;
174 val
+= skc
->skc_obj_size
* skc
->skc_obj_max
;
179 up_read(&spl_kmem_cache_sem
);
180 rc
= proc_doulongvec_minmax(&dummy
, write
, buffer
, lenp
, ppos
);
185 #endif /* DEBUG_KMEM */
188 proc_dohostid(struct ctl_table
*table
, int write
,
189 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
195 /* We can't use proc_doulongvec_minmax() in the write
196 * case here because hostid while a hex value has no
197 * leading 0x which confuses the helper function. */
198 rc
= proc_copyin_string(str
, sizeof(str
), buffer
, *lenp
);
202 spl_hostid
= simple_strtoul(str
, &end
, 16);
207 len
= snprintf(str
, sizeof(str
), "%lx", spl_hostid
);
211 rc
= proc_copyout_string(buffer
,*lenp
,str
+*ppos
,"\n");
224 slab_seq_show_headers(struct seq_file
*f
)
227 "--------------------- cache ----------"
228 "--------------------------------------------- "
231 "--- emergency ---\n");
234 " flags size alloc slabsize objsize "
237 "dlock alloc max\n");
241 slab_seq_show(struct seq_file
*f
, void *p
)
243 spl_kmem_cache_t
*skc
= p
;
245 ASSERT(skc
->skc_magic
== SKC_MAGIC
);
248 * Backed by Linux slab see /proc/slabinfo.
250 if (skc
->skc_flags
& KMC_SLAB
)
253 spin_lock(&skc
->skc_lock
);
254 seq_printf(f
, "%-36s ", skc
->skc_name
);
255 seq_printf(f
, "0x%05lx %9lu %9lu %8u %8u "
256 "%5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n",
257 (long unsigned)skc
->skc_flags
,
258 (long unsigned)(skc
->skc_slab_size
* skc
->skc_slab_total
),
259 (long unsigned)(skc
->skc_obj_size
* skc
->skc_obj_alloc
),
260 (unsigned)skc
->skc_slab_size
,
261 (unsigned)skc
->skc_obj_size
,
262 (long unsigned)skc
->skc_slab_total
,
263 (long unsigned)skc
->skc_slab_alloc
,
264 (long unsigned)skc
->skc_slab_max
,
265 (long unsigned)skc
->skc_obj_total
,
266 (long unsigned)skc
->skc_obj_alloc
,
267 (long unsigned)skc
->skc_obj_max
,
268 (long unsigned)skc
->skc_obj_deadlock
,
269 (long unsigned)skc
->skc_obj_emergency
,
270 (long unsigned)skc
->skc_obj_emergency_max
);
272 spin_unlock(&skc
->skc_lock
);
278 slab_seq_start(struct seq_file
*f
, loff_t
*pos
)
283 down_read(&spl_kmem_cache_sem
);
285 slab_seq_show_headers(f
);
287 p
= spl_kmem_cache_list
.next
;
290 if (p
== &spl_kmem_cache_list
)
294 return (list_entry(p
, spl_kmem_cache_t
, skc_list
));
298 slab_seq_next(struct seq_file
*f
, void *p
, loff_t
*pos
)
300 spl_kmem_cache_t
*skc
= p
;
303 return ((skc
->skc_list
.next
== &spl_kmem_cache_list
) ?
304 NULL
: list_entry(skc
->skc_list
.next
,spl_kmem_cache_t
,skc_list
));
308 slab_seq_stop(struct seq_file
*f
, void *v
)
310 up_read(&spl_kmem_cache_sem
);
313 static struct seq_operations slab_seq_ops
= {
314 .show
= slab_seq_show
,
315 .start
= slab_seq_start
,
316 .next
= slab_seq_next
,
317 .stop
= slab_seq_stop
,
321 proc_slab_open(struct inode
*inode
, struct file
*filp
)
323 return seq_open(filp
, &slab_seq_ops
);
326 static struct file_operations proc_slab_operations
= {
327 .open
= proc_slab_open
,
330 .release
= seq_release
,
332 #endif /* DEBUG_KMEM */
335 static struct ctl_table spl_kmem_table
[] = {
337 .procname
= "kmem_used",
338 .data
= &kmem_alloc_used
,
339 # ifdef HAVE_ATOMIC64_T
340 .maxlen
= sizeof(atomic64_t
),
342 .maxlen
= sizeof(atomic_t
),
343 # endif /* HAVE_ATOMIC64_T */
345 .proc_handler
= &proc_domemused
,
348 .procname
= "kmem_max",
349 .data
= &kmem_alloc_max
,
350 .maxlen
= sizeof(unsigned long),
351 .extra1
= &table_min
,
352 .extra2
= &table_max
,
354 .proc_handler
= &proc_doulongvec_minmax
,
357 .procname
= "slab_kmem_total",
358 .data
= (void *)(KMC_KMEM
| KMC_TOTAL
),
359 .maxlen
= sizeof(unsigned long),
360 .extra1
= &table_min
,
361 .extra2
= &table_max
,
363 .proc_handler
= &proc_doslab
,
366 .procname
= "slab_kmem_alloc",
367 .data
= (void *)(KMC_KMEM
| KMC_ALLOC
),
368 .maxlen
= sizeof(unsigned long),
369 .extra1
= &table_min
,
370 .extra2
= &table_max
,
372 .proc_handler
= &proc_doslab
,
375 .procname
= "slab_kmem_max",
376 .data
= (void *)(KMC_KMEM
| KMC_MAX
),
377 .maxlen
= sizeof(unsigned long),
378 .extra1
= &table_min
,
379 .extra2
= &table_max
,
381 .proc_handler
= &proc_doslab
,
384 .procname
= "slab_vmem_total",
385 .data
= (void *)(KMC_VMEM
| KMC_TOTAL
),
386 .maxlen
= sizeof(unsigned long),
387 .extra1
= &table_min
,
388 .extra2
= &table_max
,
390 .proc_handler
= &proc_doslab
,
393 .procname
= "slab_vmem_alloc",
394 .data
= (void *)(KMC_VMEM
| KMC_ALLOC
),
395 .maxlen
= sizeof(unsigned long),
396 .extra1
= &table_min
,
397 .extra2
= &table_max
,
399 .proc_handler
= &proc_doslab
,
402 .procname
= "slab_vmem_max",
403 .data
= (void *)(KMC_VMEM
| KMC_MAX
),
404 .maxlen
= sizeof(unsigned long),
405 .extra1
= &table_min
,
406 .extra2
= &table_max
,
408 .proc_handler
= &proc_doslab
,
412 #endif /* DEBUG_KMEM */
414 static struct ctl_table spl_kstat_table
[] = {
418 static struct ctl_table spl_table
[] = {
419 /* NB No .strategy entries have been provided since
420 * sysctl(8) prefers to go via /proc for portability.
423 .procname
= "version",
425 .maxlen
= sizeof(spl_version
),
427 .proc_handler
= &proc_dostring
,
430 .procname
= "hostid",
432 .maxlen
= sizeof(unsigned long),
434 .proc_handler
= &proc_dohostid
,
440 .child
= spl_kmem_table
,
446 .child
= spl_kstat_table
,
451 static struct ctl_table spl_dir
[] = {
460 static struct ctl_table spl_root
[] = {
463 .ctl_name
= CTL_KERN
,
465 .procname
= "kernel",
477 spl_header
= register_sysctl_table(spl_root
);
478 if (spl_header
== NULL
)
481 proc_spl
= proc_mkdir("spl", NULL
);
482 if (proc_spl
== NULL
) {
488 proc_spl_kmem
= proc_mkdir("kmem", proc_spl
);
489 if (proc_spl_kmem
== NULL
) {
494 proc_spl_kmem_slab
= proc_create_data("slab", 0444,
495 proc_spl_kmem
, &proc_slab_operations
, NULL
);
496 if (proc_spl_kmem_slab
== NULL
) {
501 #endif /* DEBUG_KMEM */
503 proc_spl_kstat
= proc_mkdir("kstat", proc_spl
);
504 if (proc_spl_kstat
== NULL
) {
510 remove_proc_entry("kstat", proc_spl
);
512 remove_proc_entry("slab", proc_spl_kmem
);
513 remove_proc_entry("kmem", proc_spl
);
515 remove_proc_entry("spl", NULL
);
516 unregister_sysctl_table(spl_header
);
525 remove_proc_entry("kstat", proc_spl
);
527 remove_proc_entry("slab", proc_spl_kmem
);
528 remove_proc_entry("kmem", proc_spl
);
530 remove_proc_entry("spl", NULL
);
532 ASSERT(spl_header
!= NULL
);
533 unregister_sysctl_table(spl_header
);