~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/proc/proc_misc.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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/sched.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 
 39 #include <asm/uaccess.h>
 40 #include <asm/pgtable.h>
 41 #include <asm/io.h>
 42 
 43 
 44 #define LOAD_INT(x) ((x) >> FSHIFT)
 45 #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
 46 /*
 47  * Warning: stuff below (imported functions) assumes that its output will fit
 48  * into one page. For some of those functions it may be wrong. Moreover, we
 49  * have a way to deal with that gracefully. Right now I used straightforward
 50  * wrappers, but this needs further analysis wrt potential overflows.
 51  */
 52 extern int get_cpuinfo(char *);
 53 extern int get_hardware_list(char *);
 54 extern int get_stram_list(char *);
 55 #ifdef CONFIG_DEBUG_MALLOC
 56 extern int get_malloc(char * buffer);
 57 #endif
 58 #ifdef CONFIG_MODULES
 59 extern int get_module_list(char *);
 60 extern int get_ksyms_list(char *, char **, off_t, int);
 61 #endif
 62 extern int get_device_list(char *);
 63 extern int get_partition_list(char *, char **, off_t, int);
 64 extern int get_filesystem_list(char *);
 65 extern int get_filesystem_info(char *);
 66 extern int get_exec_domain_list(char *);
 67 extern int get_irq_list(char *);
 68 extern int get_dma_list(char *);
 69 extern int get_locks_status (char *, char **, off_t, int);
 70 extern int get_swaparea_info (char *);
 71 #ifdef CONFIG_SGI_DS1286
 72 extern int get_ds1286_status(char *);
 73 #endif
 74 
 75 static int proc_calc_metrics(char *page, char **start, off_t off,
 76                                  int count, int *eof, int len)
 77 {
 78         if (len <= off+count) *eof = 1;
 79         *start = page + off;
 80         len -= off;
 81         if (len>count) len = count;
 82         if (len<0) len = 0;
 83         return len;
 84 }
 85 
 86 static int loadavg_read_proc(char *page, char **start, off_t off,
 87                                  int count, int *eof, void *data)
 88 {
 89         int a, b, c;
 90         int len;
 91 
 92         a = avenrun[0] + (FIXED_1/200);
 93         b = avenrun[1] + (FIXED_1/200);
 94         c = avenrun[2] + (FIXED_1/200);
 95         len = sprintf(page,"%d.%02d %d.%02d %d.%02d %d/%d %d\n",
 96                 LOAD_INT(a), LOAD_FRAC(a),
 97                 LOAD_INT(b), LOAD_FRAC(b),
 98                 LOAD_INT(c), LOAD_FRAC(c),
 99                 nr_running, nr_threads, last_pid);
100         return proc_calc_metrics(page, start, off, count, eof, len);
101 }
102 
103 static int uptime_read_proc(char *page, char **start, off_t off,
104                                  int count, int *eof, void *data)
105 {
106         unsigned long uptime;
107         unsigned long idle;
108         int len;
109 
110         uptime = jiffies;
111         idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
112 
113         /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
114            that would overflow about every five days at HZ == 100.
115            Therefore the identity a = (a / b) * b + a % b is used so that it is
116            calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100.
117            The part in front of the '+' always evaluates as 0 (mod 100). All divisions
118            in the above formulas are truncating. For HZ being a power of 10, the
119            calculations simplify to the version in the #else part (if the printf
120            format is adapted to the same number of digits as zeroes in HZ.
121          */
122 #if HZ!=100
123         len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
124                 uptime / HZ,
125                 (((uptime % HZ) * 100) / HZ) % 100,
126                 idle / HZ,
127                 (((idle % HZ) * 100) / HZ) % 100);
128 #else
129         len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
130                 uptime / HZ,
131                 uptime % HZ,
132                 idle / HZ,
133                 idle % HZ);
134 #endif
135         return proc_calc_metrics(page, start, off, count, eof, len);
136 }
137 
138 static int meminfo_read_proc(char *page, char **start, off_t off,
139                                  int count, int *eof, void *data)
140 {
141         struct sysinfo i;
142         int len;
143 
144 /*
145  * display in kilobytes.
146  */
147 #define K(x) ((x) << (PAGE_SHIFT - 10))
148 #define B(x) ((x) << PAGE_SHIFT)
149         si_meminfo(&i);
150         si_swapinfo(&i);
151         len = sprintf(page, "        total:    used:    free:  shared: buffers:  cached:\n"
152                 "Mem:  %8lu %8lu %8lu %8lu %8lu %8u\n"
153                 "Swap: %8lu %8lu %8lu\n",
154                 B(i.totalram), B(i.totalram-i.freeram), B(i.freeram),
155                 B(i.sharedram), B(i.bufferram),
156                 B(atomic_read(&page_cache_size)), B(i.totalswap),
157                 B(i.totalswap-i.freeswap), B(i.freeswap));
158         /*
159          * Tagged format, for easy grepping and expansion.
160          * The above will go away eventually, once the tools
161          * have been updated.
162          */
163         len += sprintf(page+len,
164                 "MemTotal:     %8lu kB\n"
165                 "MemFree:      %8lu kB\n"
166                 "MemShared:    %8lu kB\n"
167                 "Buffers:      %8lu kB\n"
168                 "Cached:       %8u kB\n"
169                 "Active:       %8u kB\n"
170                 "Inact_dirty:  %8u kB\n"
171                 "Inact_clean:  %8u kB\n"
172                 "Inact_target: %8lu kB\n"
173                 "HighTotal:    %8lu kB\n"
174                 "HighFree:     %8lu kB\n"
175                 "LowTotal:     %8lu kB\n"
176                 "LowFree:      %8lu kB\n"
177                 "SwapTotal:    %8lu kB\n"
178                 "SwapFree:     %8lu kB\n",
179                 K(i.totalram),
180                 K(i.freeram),
181                 K(i.sharedram),
182                 K(i.bufferram),
183                 K(atomic_read(&page_cache_size)),
184                 K(nr_active_pages),
185                 K(nr_inactive_dirty_pages),
186                 K(nr_inactive_clean_pages()),
187                 K(inactive_target),
188                 K(i.totalhigh),
189                 K(i.freehigh),
190                 K(i.totalram-i.totalhigh),
191                 K(i.freeram-i.freehigh),
192                 K(i.totalswap),
193                 K(i.freeswap));
194 
195         return proc_calc_metrics(page, start, off, count, eof, len);
196 #undef B
197 #undef K
198 }
199 
200 static int version_read_proc(char *page, char **start, off_t off,
201                                  int count, int *eof, void *data)
202 {
203         extern char *linux_banner;
204         int len;
205 
206         strcpy(page, linux_banner);
207         len = strlen(page);
208         return proc_calc_metrics(page, start, off, count, eof, len);
209 }
210 
211 static int cpuinfo_read_proc(char *page, char **start, off_t off,
212                                  int count, int *eof, void *data)
213 {
214         int len = get_cpuinfo(page);
215         return proc_calc_metrics(page, start, off, count, eof, len);
216 }
217 
218 #ifdef CONFIG_PROC_HARDWARE
219 static int hardware_read_proc(char *page, char **start, off_t off,
220                                  int count, int *eof, void *data)
221 {
222         int len = get_hardware_list(page);
223         return proc_calc_metrics(page, start, off, count, eof, len);
224 }
225 #endif
226 
227 #ifdef CONFIG_STRAM_PROC
228 static int stram_read_proc(char *page, char **start, off_t off,
229                                  int count, int *eof, void *data)
230 {
231         int len = get_stram_list(page);
232         return proc_calc_metrics(page, start, off, count, eof, len);
233 }
234 #endif
235 
236 #ifdef CONFIG_DEBUG_MALLOC
237 static int malloc_read_proc(char *page, char **start, off_t off,
238                                  int count, int *eof, void *data)
239 {
240         int len = get_malloc(page);
241         return proc_calc_metrics(page, start, off, count, eof, len);
242 }
243 #endif
244 
245 #ifdef CONFIG_MODULES
246 static int modules_read_proc(char *page, char **start, off_t off,
247                                  int count, int *eof, void *data)
248 {
249         int len = get_module_list(page);
250         return proc_calc_metrics(page, start, off, count, eof, len);
251 }
252 
253 static int ksyms_read_proc(char *page, char **start, off_t off,
254                                  int count, int *eof, void *data)
255 {
256         int len = get_ksyms_list(page, start, off, count);
257         if (len < count) *eof = 1;
258         return len;
259 }
260 #endif
261 
262 static int kstat_read_proc(char *page, char **start, off_t off,
263                                  int count, int *eof, void *data)
264 {
265         int i, len;
266         extern unsigned long total_forks;
267         unsigned long jif = jiffies;
268         unsigned int sum = 0, user = 0, nice = 0, system = 0;
269         int major, disk;
270 
271         for (i = 0 ; i < smp_num_cpus; i++) {
272                 int cpu = cpu_logical_map(i), j;
273 
274                 user += kstat.per_cpu_user[cpu];
275                 nice += kstat.per_cpu_nice[cpu];
276                 system += kstat.per_cpu_system[cpu];
277                 for (j = 0 ; j < NR_IRQS ; j++)
278                         sum += kstat.irqs[cpu][j];
279         }
280 
281         len = sprintf(page, "cpu  %u %u %u %lu\n", user, nice, system,
282                       jif * smp_num_cpus - (user + nice + system));
283         for (i = 0 ; i < smp_num_cpus; i++)
284                 len += sprintf(page + len, "cpu%d %u %u %u %lu\n",
285                         i,
286                         kstat.per_cpu_user[cpu_logical_map(i)],
287                         kstat.per_cpu_nice[cpu_logical_map(i)],
288                         kstat.per_cpu_system[cpu_logical_map(i)],
289                         jif - (  kstat.per_cpu_user[cpu_logical_map(i)] \
290                                    + kstat.per_cpu_nice[cpu_logical_map(i)] \
291                                    + kstat.per_cpu_system[cpu_logical_map(i)]));
292         len += sprintf(page + len,
293                 "page %u %u\n"
294                 "swap %u %u\n"
295                 "intr %u",
296                         kstat.pgpgin,
297                         kstat.pgpgout,
298                         kstat.pswpin,
299                         kstat.pswpout,
300                         sum
301         );
302         for (i = 0 ; i < NR_IRQS ; i++)
303                 len += sprintf(page + len, " %u", kstat_irqs(i));
304 
305         len += sprintf(page + len, "\ndisk_io: ");
306 
307         for (major = 0; major < DK_MAX_MAJOR; major++) {
308                 for (disk = 0; disk < DK_MAX_DISK; disk++) {
309                         int active = kstat.dk_drive[major][disk] +
310                                 kstat.dk_drive_rblk[major][disk] +
311                                 kstat.dk_drive_wblk[major][disk];
312                         if (active)
313                                 len += sprintf(page + len,
314                                         "(%u,%u):(%u,%u,%u,%u,%u) ",
315                                         major, disk,
316                                         kstat.dk_drive[major][disk],
317                                         kstat.dk_drive_rio[major][disk],
318                                         kstat.dk_drive_rblk[major][disk],
319                                         kstat.dk_drive_wio[major][disk],
320                                         kstat.dk_drive_wblk[major][disk]
321                         );
322                 }
323         }
324 
325         len += sprintf(page + len,
326                 "\nctxt %u\n"
327                 "btime %lu\n"
328                 "processes %lu\n",
329                 kstat.context_swtch,
330                 xtime.tv_sec - jif / HZ,
331                 total_forks);
332 
333         return proc_calc_metrics(page, start, off, count, eof, len);
334 }
335 
336 static int devices_read_proc(char *page, char **start, off_t off,
337                                  int count, int *eof, void *data)
338 {
339         int len = get_device_list(page);
340         return proc_calc_metrics(page, start, off, count, eof, len);
341 }
342 
343 static int partitions_read_proc(char *page, char **start, off_t off,
344                                  int count, int *eof, void *data)
345 {
346         int len = get_partition_list(page, start, off, count);
347         if (len < count) *eof = 1;
348         return len;
349 }
350 
351 #if !defined(CONFIG_ARCH_S390)
352 static int interrupts_read_proc(char *page, char **start, off_t off,
353                                  int count, int *eof, void *data)
354 {
355         int len = get_irq_list(page);
356         return proc_calc_metrics(page, start, off, count, eof, len);
357 }
358 #endif
359 
360 static int filesystems_read_proc(char *page, char **start, off_t off,
361                                  int count, int *eof, void *data)
362 {
363         int len = get_filesystem_list(page);
364         return proc_calc_metrics(page, start, off, count, eof, len);
365 }
366 
367 static int dma_read_proc(char *page, char **start, off_t off,
368                                  int count, int *eof, void *data)
369 {
370         int len = get_dma_list(page);
371         return proc_calc_metrics(page, start, off, count, eof, len);
372 }
373 
374 static int ioports_read_proc(char *page, char **start, off_t off,
375                                  int count, int *eof, void *data)
376 {
377         int len = get_ioport_list(page);
378         return proc_calc_metrics(page, start, off, count, eof, len);
379 }
380 
381 static int cmdline_read_proc(char *page, char **start, off_t off,
382                                  int count, int *eof, void *data)
383 {
384         extern char saved_command_line[];
385         int len;
386 
387         len = sprintf(page, "%s\n", saved_command_line);
388         len = strlen(page);
389         return proc_calc_metrics(page, start, off, count, eof, len);
390 }
391 
392 #ifdef CONFIG_SGI_DS1286
393 static int ds1286_read_proc(char *page, char **start, off_t off,
394                                  int count, int *eof, void *data)
395 {
396         int len = get_ds1286_status(page);
397         return proc_calc_metrics(page, start, off, count, eof, len);
398 }
399 #endif
400 
401 static int locks_read_proc(char *page, char **start, off_t off,
402                                  int count, int *eof, void *data)
403 {
404         int len;
405         lock_kernel();
406         len = get_locks_status(page, start, off, count);
407         unlock_kernel();
408         if (len < count) *eof = 1;
409         return len;
410 }
411 
412 static int mounts_read_proc(char *page, char **start, off_t off,
413                                  int count, int *eof, void *data)
414 {
415         int len = get_filesystem_info(page);
416         return proc_calc_metrics(page, start, off, count, eof, len);
417 }
418 
419 static int execdomains_read_proc(char *page, char **start, off_t off,
420                                  int count, int *eof, void *data)
421 {
422         int len = get_exec_domain_list(page);
423         return proc_calc_metrics(page, start, off, count, eof, len);
424 }
425 
426 static int swaps_read_proc(char *page, char **start, off_t off,
427                                  int count, int *eof, void *data)
428 {
429         int len = get_swaparea_info(page);
430         return proc_calc_metrics(page, start, off, count, eof, len);
431 }
432 
433 static int memory_read_proc(char *page, char **start, off_t off,
434                                  int count, int *eof, void *data)
435 {
436         int len = get_mem_list(page);
437         return proc_calc_metrics(page, start, off, count, eof, len);
438 }
439 
440 /*
441  * This function accesses profiling information. The returned data is
442  * binary: the sampling step and the actual contents of the profile
443  * buffer. Use of the program readprofile is recommended in order to
444  * get meaningful info out of these data.
445  */
446 static ssize_t read_profile(struct file *file, char *buf,
447                             size_t count, loff_t *ppos)
448 {
449         unsigned long p = *ppos;
450         ssize_t read;
451         char * pnt;
452         unsigned int sample_step = 1 << prof_shift;
453 
454         if (p >= (prof_len+1)*sizeof(unsigned int))
455                 return 0;
456         if (count > (prof_len+1)*sizeof(unsigned int) - p)
457                 count = (prof_len+1)*sizeof(unsigned int) - p;
458         read = 0;
459 
460         while (p < sizeof(unsigned int) && count > 0) {
461                 put_user(*((char *)(&sample_step)+p),buf);
462                 buf++; p++; count--; read++;
463         }
464         pnt = (char *)prof_buffer + p - sizeof(unsigned int);
465         copy_to_user(buf,(void *)pnt,count);
466         read += count;
467         *ppos += read;
468         return read;
469 }
470 
471 /*
472  * Writing to /proc/profile resets the counters
473  *
474  * Writing a 'profiling multiplier' value into it also re-sets the profiling
475  * interrupt frequency, on architectures that support this.
476  */
477 static ssize_t write_profile(struct file * file, const char * buf,
478                              size_t count, loff_t *ppos)
479 {
480 #ifdef CONFIG_SMP
481         extern int setup_profiling_timer (unsigned int multiplier);
482 
483         if (count==sizeof(int)) {
484                 unsigned int multiplier;
485 
486                 if (copy_from_user(&multiplier, buf, sizeof(int)))
487                         return -EFAULT;
488 
489                 if (setup_profiling_timer(multiplier))
490                         return -EINVAL;
491         }
492 #endif
493 
494         memset(prof_buffer, 0, prof_len * sizeof(*prof_buffer));
495         return count;
496 }
497 
498 static struct file_operations proc_profile_operations = {
499         read:           read_profile,
500         write:          write_profile,
501 };
502 
503 struct proc_dir_entry *proc_root_kcore;
504 
505 void __init proc_misc_init(void)
506 {
507         struct proc_dir_entry *entry;
508         static struct {
509                 char *name;
510                 int (*read_proc)(char*,char**,off_t,int,int*,void*);
511         } *p, simple_ones[] = {
512                 {"loadavg",     loadavg_read_proc},
513                 {"uptime",      uptime_read_proc},
514                 {"meminfo",     meminfo_read_proc},
515                 {"version",     version_read_proc},
516                 {"cpuinfo",     cpuinfo_read_proc},
517 #ifdef CONFIG_PROC_HARDWARE
518                 {"hardware",    hardware_read_proc},
519 #endif
520 #ifdef CONFIG_STRAM_PROC
521                 {"stram",       stram_read_proc},
522 #endif
523 #ifdef CONFIG_DEBUG_MALLOC
524                 {"malloc",      malloc_read_proc},
525 #endif
526 #ifdef CONFIG_MODULES
527                 {"modules",     modules_read_proc},
528                 {"ksyms",       ksyms_read_proc},
529 #endif
530                 {"stat",        kstat_read_proc},
531                 {"devices",     devices_read_proc},
532                 {"partitions",  partitions_read_proc},
533 #if !defined(CONFIG_ARCH_S390)
534                 {"interrupts",  interrupts_read_proc},
535 #endif
536                 {"filesystems", filesystems_read_proc},
537                 {"dma",         dma_read_proc},
538                 {"ioports",     ioports_read_proc},
539                 {"cmdline",     cmdline_read_proc},
540 #ifdef CONFIG_SGI_DS1286
541                 {"rtc",         ds1286_read_proc},
542 #endif
543                 {"locks",       locks_read_proc},
544                 {"mounts",      mounts_read_proc},
545                 {"swaps",       swaps_read_proc},
546                 {"iomem",       memory_read_proc},
547                 {"execdomains", execdomains_read_proc},
548                 {NULL,}
549         };
550         for (p = simple_ones; p->name; p++)
551                 create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL);
552 
553         /* And now for trickier ones */
554         entry = create_proc_entry("kmsg", S_IRUSR, &proc_root);
555         if (entry)
556                 entry->proc_fops = &proc_kmsg_operations;
557         proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL);
558         if (proc_root_kcore) {
559                 proc_root_kcore->proc_fops = &proc_kcore_operations;
560                 proc_root_kcore->size =
561                                 (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE;
562         }
563         if (prof_shift) {
564                 entry = create_proc_entry("profile", S_IWUSR | S_IRUGO, NULL);
565                 if (entry) {
566                         entry->proc_fops = &proc_profile_operations;
567                         entry->size = (1+prof_len) * sizeof(unsigned int);
568                 }
569         }
570 #ifdef __powerpc__
571         {
572                 extern struct file_operations ppc_htab_operations;
573                 entry = create_proc_entry("ppc_htab", S_IRUGO|S_IWUSR, NULL);
574                 if (entry)
575                         entry->proc_fops = &ppc_htab_operations;
576         }
577 #endif
578         entry = create_proc_read_entry("slabinfo", S_IWUSR | S_IRUGO, NULL,
579                                        slabinfo_read_proc, NULL);
580         if (entry)
581                 entry->write_proc = slabinfo_write_proc;
582 }
583 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.