[PATCH] new helpers for /proc
[opensuse:kernel.git] / fs / proc / proc_misc.c
1 /*
2  *  linux/fs/proc/proc_misc.c
3  *
4  *  linux/fs/proc/array.c
5  *  Copyright (C) 1992  by Linus Torvalds
6  *  based on ideas by Darren Senn
7  *
8  *  This used to be the part of array.c. See the rest of history and credits
9  *  there. I took this into a separate file and switched the thing to generic
10  *  proc_file_inode_operations, leaving in array.c only per-process stuff.
11  *  Inumbers allocation made dynamic (via create_proc_entry()).  AV, May 1999.
12  *
13  * Changes:
14  * Fulton Green      :  Encapsulated position metric calculations.
15  *                      <kernel@FultonGreen.com>
16  */
17
18 #include <linux/types.h>
19 #include <linux/errno.h>
20 #include <linux/time.h>
21 #include <linux/kernel.h>
22 #include <linux/kernel_stat.h>
23 #include <linux/tty.h>
24 #include <linux/string.h>
25 #include <linux/mman.h>
26 #include <linux/proc_fs.h>
27 #include <linux/ioport.h>
28 #include <linux/config.h>
29 #include <linux/mm.h>
30 #include <linux/pagemap.h>
31 #include <linux/swap.h>
32 #include <linux/slab.h>
33 #include <linux/smp.h>
34 #include <linux/signal.h>
35 #include <linux/module.h>
36 #include <linux/init.h>
37 #include <linux/smp_lock.h>
38 #include <linux/seq_file.h>
39
40 #include <asm/uaccess.h>
41 #include <asm/pgtable.h>
42 #include <asm/io.h>
43
44
45 #define LOAD_INT(x) ((x) >> FSHIFT)
46 #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
47 /*
48  * Warning: stuff below (imported functions) assumes that its output will fit
49  * into one page. For some of those functions it may be wrong. Moreover, we
50  * have a way to deal with that gracefully. Right now I used straightforward
51  * wrappers, but this needs further analysis wrt potential overflows.
52  */
53 extern int get_hardware_list(char *);
54 extern int get_stram_list(char *);
55 extern int get_device_list(char *);
56 extern int get_filesystem_list(char *);
57 extern int get_exec_domain_list(char *);
58 extern int get_dma_list(char *);
59 extern int get_locks_status (char *, char **, off_t, int);
60 extern int get_swaparea_info (char *);
61 #ifdef CONFIG_SGI_DS1286
62 extern int get_ds1286_status(char *);
63 #endif
64
65 static int proc_calc_metrics(char *page, char **start, off_t off,
66                                  int count, int *eof, int len)
67 {
68         if (len <= off+count) *eof = 1;
69         *start = page + off;
70         len -= off;
71         if (len>count) len = count;
72         if (len<0) len = 0;
73         return len;
74 }
75
76 static int loadavg_read_proc(char *page, char **start, off_t off,
77                                  int count, int *eof, void *data)
78 {
79         int a, b, c;
80         int len;
81
82         a = avenrun[0] + (FIXED_1/200);
83         b = avenrun[1] + (FIXED_1/200);
84         c = avenrun[2] + (FIXED_1/200);
85         len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n",
86                 LOAD_INT(a), LOAD_FRAC(a),
87                 LOAD_INT(b), LOAD_FRAC(b),
88                 LOAD_INT(c), LOAD_FRAC(c),
89                 nr_running(), nr_threads, last_pid);
90         return proc_calc_metrics(page, start, off, count, eof, len);
91 }
92
93 static int uptime_read_proc(char *page, char **start, off_t off,
94                                  int count, int *eof, void *data)
95 {
96         unsigned long uptime;
97         unsigned long idle;
98         int len;
99
100         uptime = jiffies;
101         idle = init_task.times.tms_utime + init_task.times.tms_stime;
102
103         /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
104            that would overflow about every five days at HZ == 100.
105            Therefore the identity a = (a / b) * b + a % b is used so that it is
106            calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100.
107            The part in front of the '+' always evaluates as 0 (mod 100). All divisions
108            in the above formulas are truncating. For HZ being a power of 10, the
109            calculations simplify to the version in the #else part (if the printf
110            format is adapted to the same number of digits as zeroes in HZ.
111          */
112 #if HZ!=100
113         len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
114                 uptime / HZ,
115                 (((uptime % HZ) * 100) / HZ) % 100,
116                 idle / HZ,
117                 (((idle % HZ) * 100) / HZ) % 100);
118 #else
119         len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
120                 uptime / HZ,
121                 uptime % HZ,
122                 idle / HZ,
123                 idle % HZ);
124 #endif
125         return proc_calc_metrics(page, start, off, count, eof, len);
126 }
127
128 static int meminfo_read_proc(char *page, char **start, off_t off,
129                                  int count, int *eof, void *data)
130 {
131         struct sysinfo i;
132         int len;
133         struct page_state ps;
134
135         get_page_state(&ps);
136 /*
137  * display in kilobytes.
138  */
139 #define K(x) ((x) << (PAGE_SHIFT - 10))
140         si_meminfo(&i);
141         si_swapinfo(&i);
142
143         /*
144          * Tagged format, for easy grepping and expansion.
145          */
146         len = sprintf(page,
147                 "MemTotal:     %8lu kB\n"
148                 "MemFree:      %8lu kB\n"
149                 "MemShared:    %8lu kB\n"
150                 "Cached:       %8lu kB\n"
151                 "SwapCached:   %8lu kB\n"
152                 "Active:       %8u kB\n"
153                 "Inactive:     %8u kB\n"
154                 "HighTotal:    %8lu kB\n"
155                 "HighFree:     %8lu kB\n"
156                 "LowTotal:     %8lu kB\n"
157                 "LowFree:      %8lu kB\n"
158                 "SwapTotal:    %8lu kB\n"
159                 "SwapFree:     %8lu kB\n"
160                 "Dirty:        %8lu kB\n"
161                 "Writeback:    %8lu kB\n",
162                 K(i.totalram),
163                 K(i.freeram),
164                 K(i.sharedram),
165                 K(ps.nr_pagecache-swapper_space.nrpages),
166                 K(swapper_space.nrpages),
167                 K(nr_active_pages),
168                 K(nr_inactive_pages),
169                 K(i.totalhigh),
170                 K(i.freehigh),
171                 K(i.totalram-i.totalhigh),
172                 K(i.freeram-i.freehigh),
173                 K(i.totalswap),
174                 K(i.freeswap),
175                 K(ps.nr_dirty),
176                 K(ps.nr_writeback)
177                 );
178
179         return proc_calc_metrics(page, start, off, count, eof, len);
180 #undef K
181 }
182
183 static int version_read_proc(char *page, char **start, off_t off,
184                                  int count, int *eof, void *data)
185 {
186         extern char *linux_banner;
187         int len;
188
189         strcpy(page, linux_banner);
190         len = strlen(page);
191         return proc_calc_metrics(page, start, off, count, eof, len);
192 }
193
194 extern struct seq_operations cpuinfo_op;
195 static int cpuinfo_open(struct inode *inode, struct file *file)
196 {
197         return seq_open(file, &cpuinfo_op);
198 }
199 static struct file_operations proc_cpuinfo_operations = {
200         open:           cpuinfo_open,
201         read:           seq_read,
202         llseek:         seq_lseek,
203         release:        seq_release,
204 };
205
206 #ifdef CONFIG_PROC_HARDWARE
207 static int hardware_read_proc(char *page, char **start, off_t off,
208                                  int count, int *eof, void *data)
209 {
210         int len = get_hardware_list(page);
211         return proc_calc_metrics(page, start, off, count, eof, len);
212 }
213 #endif
214
215 #ifdef CONFIG_STRAM_PROC
216 static int stram_read_proc(char *page, char **start, off_t off,
217                                  int count, int *eof, void *data)
218 {
219         int len = get_stram_list(page);
220         return proc_calc_metrics(page, start, off, count, eof, len);
221 }
222 #endif
223
224 extern struct seq_operations partitions_op;
225 static int partitions_open(struct inode *inode, struct file *file)
226 {
227         return seq_open(file, &partitions_op);
228 }
229 static struct file_operations proc_partitions_operations = {
230         open:           partitions_open,
231         read:           seq_read,
232         llseek:         seq_lseek,
233         release:        seq_release,
234 };
235
236 #ifdef CONFIG_MODULES
237 extern struct seq_operations modules_op;
238 static int modules_open(struct inode *inode, struct file *file)
239 {
240         return seq_open(file, &modules_op);
241 }
242 static struct file_operations proc_modules_operations = {
243         open:           modules_open,
244         read:           seq_read,
245         llseek:         seq_lseek,
246         release:        seq_release,
247 };
248 extern struct seq_operations ksyms_op;
249 static int ksyms_open(struct inode *inode, struct file *file)
250 {
251         return seq_open(file, &ksyms_op);
252 }
253 static struct file_operations proc_ksyms_operations = {
254         open:           ksyms_open,
255         read:           seq_read,
256         llseek:         seq_lseek,
257         release:        seq_release,
258 };
259 #endif
260
261 extern struct seq_operations slabinfo_op;
262 extern ssize_t slabinfo_write(struct file *, const char *, size_t, loff_t *);
263 static int slabinfo_open(struct inode *inode, struct file *file)
264 {
265         return seq_open(file, &slabinfo_op);
266 }
267 static struct file_operations proc_slabinfo_operations = {
268         open:           slabinfo_open,
269         read:           seq_read,
270         write:          slabinfo_write,
271         llseek:         seq_lseek,
272         release:        seq_release,
273 };
274
275 static int kstat_read_proc(char *page, char **start, off_t off,
276                                  int count, int *eof, void *data)
277 {
278         int i, len;
279         extern unsigned long total_forks;
280         unsigned long jif = jiffies;
281         unsigned int sum = 0, user = 0, nice = 0, system = 0;
282         int major, disk;
283
284         for (i = 0 ; i < smp_num_cpus; i++) {
285                 int cpu = cpu_logical_map(i), j;
286
287                 user += kstat.per_cpu_user[cpu];
288                 nice += kstat.per_cpu_nice[cpu];
289                 system += kstat.per_cpu_system[cpu];
290 #if !defined(CONFIG_ARCH_S390)
291                 for (j = 0 ; j < NR_IRQS ; j++)
292                         sum += kstat.irqs[cpu][j];
293 #endif
294         }
295
296         len = sprintf(page, "cpu  %u %u %u %lu\n", user, nice, system,
297                       jif * smp_num_cpus - (user + nice + system));
298         for (i = 0 ; i < smp_num_cpus; i++)
299                 len += sprintf(page + len, "cpu%d %u %u %u %lu\n",
300                         i,
301                         kstat.per_cpu_user[cpu_logical_map(i)],
302                         kstat.per_cpu_nice[cpu_logical_map(i)],
303                         kstat.per_cpu_system[cpu_logical_map(i)],
304                         jif - (  kstat.per_cpu_user[cpu_logical_map(i)] \
305                                    + kstat.per_cpu_nice[cpu_logical_map(i)] \
306                                    + kstat.per_cpu_system[cpu_logical_map(i)]));
307         len += sprintf(page + len,
308                 "page %u %u\n"
309                 "swap %u %u\n"
310                 "intr %u",
311                         kstat.pgpgin >> 1,
312                         kstat.pgpgout >> 1,
313                         kstat.pswpin,
314                         kstat.pswpout,
315                         sum
316         );
317 #if !defined(CONFIG_ARCH_S390)
318         for (i = 0 ; i < NR_IRQS ; i++)
319                 len += sprintf(page + len, " %u", kstat_irqs(i));
320 #endif
321
322         len += sprintf(page + len, "\ndisk_io: ");
323
324         for (major = 0; major < DK_MAX_MAJOR; major++) {
325                 for (disk = 0; disk < DK_MAX_DISK; disk++) {
326                         int active = kstat.dk_drive[major][disk] +
327                                 kstat.dk_drive_rblk[major][disk] +
328                                 kstat.dk_drive_wblk[major][disk];
329                         if (active)
330                                 len += sprintf(page + len,
331                                         "(%u,%u):(%u,%u,%u,%u,%u) ",
332                                         major, disk,
333                                         kstat.dk_drive[major][disk],
334                                         kstat.dk_drive_rio[major][disk],
335                                         kstat.dk_drive_rblk[major][disk],
336                                         kstat.dk_drive_wio[major][disk],
337                                         kstat.dk_drive_wblk[major][disk]
338                         );
339                 }
340         }
341
342         len += sprintf(page + len,
343                 "\nctxt %lu\n"
344                 "btime %lu\n"
345                 "processes %lu\n",
346                 nr_context_switches(),
347                 xtime.tv_sec - jif / HZ,
348                 total_forks);
349
350         return proc_calc_metrics(page, start, off, count, eof, len);
351 }
352
353 static int devices_read_proc(char *page, char **start, off_t off,
354                                  int count, int *eof, void *data)
355 {
356         int len = get_device_list(page);
357         return proc_calc_metrics(page, start, off, count, eof, len);
358 }
359
360 extern int show_interrupts(struct seq_file *p, void *v);
361 static int interrupts_open(struct inode *inode, struct file *file)
362 {
363         unsigned size = PAGE_SIZE;
364         /*
365          * probably should depend on NR_CPUS, but that's only rough estimate;
366          * if we'll need more it will be given,
367          */
368         char *buf = kmalloc(size, GFP_KERNEL);
369         struct seq_file *m;
370         int res;
371
372         if (!buf)
373                 return -ENOMEM;
374         res = single_open(file, show_interrupts, NULL);
375         if (!res) {
376                 m = file->private_data;
377                 m->buf = buf;
378                 m->size = size;
379         } else
380                 kfree(buf);
381         return res;
382 }
383 static struct file_operations proc_interrupts_operations = {
384         open:           interrupts_open,
385         read:           seq_read,
386         llseek:         seq_lseek,
387         release:        single_release,
388 };
389
390 static int filesystems_read_proc(char *page, char **start, off_t off,
391                                  int count, int *eof, void *data)
392 {
393         int len = get_filesystem_list(page);
394         return proc_calc_metrics(page, start, off, count, eof, len);
395 }
396
397 static int dma_read_proc(char *page, char **start, off_t off,
398                                  int count, int *eof, void *data)
399 {
400         int len = get_dma_list(page);
401         return proc_calc_metrics(page, start, off, count, eof, len);
402 }
403
404 static int ioports_read_proc(char *page, char **start, off_t off,
405                                  int count, int *eof, void *data)
406 {
407         int len = get_ioport_list(page);
408         return proc_calc_metrics(page, start, off, count, eof, len);
409 }
410
411 static int cmdline_read_proc(char *page, char **start, off_t off,
412                                  int count, int *eof, void *data)
413 {
414         extern char saved_command_line[];
415         int len;
416
417         len = sprintf(page, "%s\n", saved_command_line);
418         len = strlen(page);
419         return proc_calc_metrics(page, start, off, count, eof, len);
420 }
421
422 #ifdef CONFIG_SGI_DS1286
423 static int ds1286_read_proc(char *page, char **start, off_t off,
424                                  int count, int *eof, void *data)
425 {
426         int len = get_ds1286_status(page);
427         return proc_calc_metrics(page, start, off, count, eof, len);
428 }
429 #endif
430
431 static int locks_read_proc(char *page, char **start, off_t off,
432                                  int count, int *eof, void *data)
433 {
434         int len;
435         lock_kernel();
436         len = get_locks_status(page, start, off, count);
437         unlock_kernel();
438         if (len < count) *eof = 1;
439         return len;
440 }
441
442 static int execdomains_read_proc(char *page, char **start, off_t off,
443                                  int count, int *eof, void *data)
444 {
445         int len = get_exec_domain_list(page);
446         return proc_calc_metrics(page, start, off, count, eof, len);
447 }
448
449 static int swaps_read_proc(char *page, char **start, off_t off,
450                                  int count, int *eof, void *data)
451 {
452         int len = get_swaparea_info(page);
453         return proc_calc_metrics(page, start, off, count, eof, len);
454 }
455
456 static int memory_read_proc(char *page, char **start, off_t off,
457                                  int count, int *eof, void *data)
458 {
459         int len = get_mem_list(page);
460         return proc_calc_metrics(page, start, off, count, eof, len);
461 }
462
463 /*
464  * This function accesses profiling information. The returned data is
465  * binary: the sampling step and the actual contents of the profile
466  * buffer. Use of the program readprofile is recommended in order to
467  * get meaningful info out of these data.
468  */
469 static ssize_t read_profile(struct file *file, char *buf,
470                             size_t count, loff_t *ppos)
471 {
472         unsigned long p = *ppos;
473         ssize_t read;
474         char * pnt;
475         unsigned int sample_step = 1 << prof_shift;
476
477         if (p >= (prof_len+1)*sizeof(unsigned int))
478                 return 0;
479         if (count > (prof_len+1)*sizeof(unsigned int) - p)
480                 count = (prof_len+1)*sizeof(unsigned int) - p;
481         read = 0;
482
483         while (p < sizeof(unsigned int) && count > 0) {
484                 put_user(*((char *)(&sample_step)+p),buf);
485                 buf++; p++; count--; read++;
486         }
487         pnt = (char *)prof_buffer + p - sizeof(unsigned int);
488         copy_to_user(buf,(void *)pnt,count);
489         read += count;
490         *ppos += read;
491         return read;
492 }
493
494 /*
495  * Writing to /proc/profile resets the counters
496  *
497  * Writing a 'profiling multiplier' value into it also re-sets the profiling
498  * interrupt frequency, on architectures that support this.
499  */
500 static ssize_t write_profile(struct file * file, const char * buf,
501                              size_t count, loff_t *ppos)
502 {
503 #ifdef CONFIG_SMP
504         extern int setup_profiling_timer (unsigned int multiplier);
505
506         if (count==sizeof(int)) {
507                 unsigned int multiplier;
508
509                 if (copy_from_user(&multiplier, buf, sizeof(int)))
510                         return -EFAULT;
511
512                 if (setup_profiling_timer(multiplier))
513                         return -EINVAL;
514         }
515 #endif
516
517         memset(prof_buffer, 0, prof_len * sizeof(*prof_buffer));
518         return count;
519 }
520
521 static struct file_operations proc_profile_operations = {
522         read:           read_profile,
523         write:          write_profile,
524 };
525
526 struct proc_dir_entry *proc_root_kcore;
527
528 static void create_seq_entry(char *name, mode_t mode, struct file_operations *f)
529 {
530         struct proc_dir_entry *entry;
531         entry = create_proc_entry(name, mode, NULL);
532         if (entry)
533                 entry->proc_fops = f;
534 }
535
536 void __init proc_misc_init(void)
537 {
538         struct proc_dir_entry *entry;
539         static struct {
540                 char *name;
541                 int (*read_proc)(char*,char**,off_t,int,int*,void*);
542         } *p, simple_ones[] = {
543                 {"loadavg",     loadavg_read_proc},
544                 {"uptime",      uptime_read_proc},
545                 {"meminfo",     meminfo_read_proc},
546                 {"version",     version_read_proc},
547 #ifdef CONFIG_PROC_HARDWARE
548                 {"hardware",    hardware_read_proc},
549 #endif
550 #ifdef CONFIG_STRAM_PROC
551                 {"stram",       stram_read_proc},
552 #endif
553                 {"stat",        kstat_read_proc},
554                 {"devices",     devices_read_proc},
555                 {"filesystems", filesystems_read_proc},
556                 {"dma",         dma_read_proc},
557                 {"ioports",     ioports_read_proc},
558                 {"cmdline",     cmdline_read_proc},
559 #ifdef CONFIG_SGI_DS1286
560                 {"rtc",         ds1286_read_proc},
561 #endif
562                 {"locks",       locks_read_proc},
563                 {"swaps",       swaps_read_proc},
564                 {"iomem",       memory_read_proc},
565                 {"execdomains", execdomains_read_proc},
566                 {NULL,}
567         };
568         for (p = simple_ones; p->name; p++)
569                 create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL);
570
571         proc_symlink("mounts", NULL, "self/mounts");
572
573         /* And now for trickier ones */
574         entry = create_proc_entry("kmsg", S_IRUSR, &proc_root);
575         if (entry)
576                 entry->proc_fops = &proc_kmsg_operations;
577         create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
578         create_seq_entry("partitions", 0, &proc_partitions_operations);
579         create_seq_entry("interrupts", 0, &proc_interrupts_operations);
580         create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
581 #ifdef CONFIG_MODULES
582         create_seq_entry("modules", 0, &proc_modules_operations);
583         create_seq_entry("ksyms", 0, &proc_ksyms_operations);
584 #endif
585         proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL);
586         if (proc_root_kcore) {
587                 proc_root_kcore->proc_fops = &proc_kcore_operations;
588                 proc_root_kcore->size =
589                                 (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE;
590         }
591         if (prof_shift) {
592                 entry = create_proc_entry("profile", S_IWUSR | S_IRUGO, NULL);
593                 if (entry) {
594                         entry->proc_fops = &proc_profile_operations;
595                         entry->size = (1+prof_len) * sizeof(unsigned int);
596                 }
597         }
598 #ifdef CONFIG_PPC32
599         {
600                 extern struct file_operations ppc_htab_operations;
601                 entry = create_proc_entry("ppc_htab", S_IRUGO|S_IWUSR, NULL);
602                 if (entry)
603                         entry->proc_fops = &ppc_htab_operations;
604         }
605 #endif
606 }