diff options
author | Martin Baulig <martin@src.gnome.org> | 1999-05-03 20:06:40 +0000 |
---|---|---|
committer | Martin Baulig <martin@src.gnome.org> | 1999-05-03 20:06:40 +0000 |
commit | 70b65c05e59938434d6317077e0a44e8666eaa54 (patch) | |
tree | c08d92e7d6d07c22e04d3feae3d367774bf44ebf /kernel | |
parent | 293995a277a6362485afeffdc2f223b76d0c288b (diff) | |
download | libgtop-70b65c05e59938434d6317077e0a44e8666eaa54.tar.gz |
Merged a few bug fixes from the HEAD.
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/sysctl/.cvsignore | 1 | ||||
-rw-r--r-- | kernel/sysctl/Makefile | 22 | ||||
-rw-r--r-- | kernel/sysctl/libgtop.c | 1268 | ||||
-rw-r--r-- | kernel/sysctl/libgtop.h | 242 | ||||
-rw-r--r-- | kernel/sysctl/libgtop_syms.c | 30 | ||||
-rw-r--r-- | kernel/sysctl/main.c | 4 | ||||
-rw-r--r-- | kernel/sysctl/patch-2.2.1 | 81 |
7 files changed, 1648 insertions, 0 deletions
diff --git a/kernel/sysctl/.cvsignore b/kernel/sysctl/.cvsignore new file mode 100644 index 00000000..9ff296a7 --- /dev/null +++ b/kernel/sysctl/.cvsignore @@ -0,0 +1 @@ +*.flags diff --git a/kernel/sysctl/Makefile b/kernel/sysctl/Makefile new file mode 100644 index 00000000..77dd277a --- /dev/null +++ b/kernel/sysctl/Makefile @@ -0,0 +1,22 @@ +# +# Makefile for the LibGTop linux sysctl interface. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +O_TARGET := kernel.o +ifeq ($(CONFIG_LIBGTOP),y) +O_OJBS := main.o libgtop.o +else +O_OBJS := main.o +endif +OX_OBJS := libgtop_syms.o + +ifeq ($(CONFIG_LIBGTOP),m) +M_OBJS := libgtop.o +endif + +include $(TOPDIR)/Rules.make diff --git a/kernel/sysctl/libgtop.c b/kernel/sysctl/libgtop.c new file mode 100644 index 00000000..8c769644 --- /dev/null +++ b/kernel/sysctl/libgtop.c @@ -0,0 +1,1268 @@ +/* + * linux/libgtop/module.c + * Copyright (C) 1999 Martin Baulig + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/kernel_stat.h> +#include <linux/tty.h> +#include <linux/user.h> +#include <linux/a.out.h> +#include <linux/string.h> +#include <linux/mman.h> +#include <linux/proc_fs.h> +#include <linux/ioport.h> +#include <linux/config.h> +#include <linux/mm.h> +#include <linux/pagemap.h> +#include <linux/swap.h> +#include <linux/slab.h> +#include <linux/smp.h> +#include <linux/signal.h> + +#include <asm/uaccess.h> +#include <asm/pgtable.h> +#include <asm/io.h> + +#include <linux/sysctl.h> +#include <linux/module.h> + +#include <linux/libgtop.h> + +EXPORT_NO_SYMBOLS; + +static int system_ctl_handler (ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, void *newval, + size_t newlen, void **context); + +static int proc_ctl_handler (ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, void *newval, + size_t newlen, void **context); + +static int proc_args_ctl_handler (ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, + void **context); + +static int proc_maps_ctl_handler (ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, + void **context); + +#if CONFIG_NET + +#include <linux/netdevice.h> + +static int proc_net_ctl_handler (ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, + void **context); + +#endif /* CONFIG_NET */ + +static int libgtop_sysctl_version = 2; +static int libgtop_update_expensive = 5000; + +static struct ctl_table_header *libgtop_sysctl_header = NULL; + +static libgtop_stat_t libgtop_stat; +static unsigned int libgtop_mem_timestamp = 0; +static libgtop_mem_t libgtop_mem; +static unsigned int libgtop_swap_timestamp = 0; +static libgtop_swap_t libgtop_swap; + +static libgtop_proclist_t libgtop_proclist; +static libgtop_proc_state_t libgtop_proc_state; +static libgtop_proc_kernel_t libgtop_proc_kernel; +static libgtop_proc_segment_t libgtop_proc_segment; +static libgtop_proc_mem_t libgtop_proc_mem; +static libgtop_proc_signal_t libgtop_proc_signal; + +static ctl_table libgtop_table[]; +static ctl_table libgtop_root_table[] = { + {CTL_LIBGTOP, "libgtop", NULL, 0, 0555, libgtop_table}, + {0} +}; + +#ifdef MODULE +static +#endif +ctl_table libgtop_table[] = { + {LIBGTOP_VERSION, "version", &libgtop_sysctl_version, + sizeof (int), 0444, NULL, &proc_dointvec}, + {LIBGTOP_UPDATE_EXPENSIVE, "update_expensive", + &libgtop_update_expensive, sizeof (int), 0664, NULL, &proc_dointvec}, + {LIBGTOP_STAT, NULL, &libgtop_stat, sizeof (libgtop_stat), + 0444, NULL, NULL, &system_ctl_handler}, + {LIBGTOP_MEM, NULL, &libgtop_mem, sizeof (libgtop_mem), + 0444, NULL, NULL, &system_ctl_handler}, + {LIBGTOP_SWAP, NULL, &libgtop_swap, sizeof (libgtop_swap), + 0444, NULL, NULL, &system_ctl_handler}, + {LIBGTOP_PROCLIST, NULL, &libgtop_proclist, sizeof (libgtop_proclist), + 0444, NULL, NULL, &system_ctl_handler}, + {LIBGTOP_PROC_STATE, NULL, &libgtop_proc_state, + sizeof (libgtop_proc_state), 0444, NULL, NULL, &proc_ctl_handler}, + {LIBGTOP_PROC_KERNEL, NULL, &libgtop_proc_kernel, + sizeof (libgtop_proc_kernel), 0444, NULL, NULL, &proc_ctl_handler}, + {LIBGTOP_PROC_SEGMENT, NULL, &libgtop_proc_segment, + sizeof (libgtop_proc_segment), 0444, NULL, NULL, &proc_ctl_handler}, + {LIBGTOP_PROC_MEM, NULL, &libgtop_proc_mem, + sizeof (libgtop_proc_mem), 0444, NULL, NULL, &proc_ctl_handler}, + {LIBGTOP_PROC_SIGNAL, NULL, &libgtop_proc_signal, + sizeof (libgtop_proc_signal), 0444, NULL, NULL, &proc_ctl_handler}, + {LIBGTOP_PROC_ARGS, NULL, NULL, 0, 0444, NULL, NULL, + &proc_args_ctl_handler}, + {LIBGTOP_PROC_MAPS, NULL, NULL, 0, 0444, NULL, NULL, + &proc_maps_ctl_handler}, +#if CONFIG_NET + /* You cannot actually "write" this value; we just use this to + * pass the device name as parameter. */ + {LIBGTOP_NETLOAD, NULL, NULL, 0, 0666, NULL, NULL, + &proc_net_ctl_handler}, +#endif + {0} +}; + +#ifdef MODULE +static void +libgtop_sysctl_register(void) +{ + static int initialized = 0; + + if (initialized == 1) + return; + + libgtop_sysctl_header = register_sysctl_table(libgtop_root_table, 1); + initialized = 1; +} + +static void +libgtop_sysctl_unregister(void) +{ + unregister_sysctl_table(libgtop_sysctl_header); +} + +int init_module(void) +{ + libgtop_sysctl_register(); + return 0; +} + +void cleanup_module(void) +{ + libgtop_sysctl_unregister(); +} + +#endif /* MODULE */ + +/* + * These bracket the sleeping functions.. + */ +extern void scheduling_functions_start_here(void); +extern void scheduling_functions_end_here(void); +#define first_sched ((unsigned long) scheduling_functions_start_here) +#define last_sched ((unsigned long) scheduling_functions_end_here) + +static unsigned long +get_wchan (struct task_struct *p) +{ + if (!p || p == current || p->state == TASK_RUNNING) + return 0; +#if defined(__i386__) + { + unsigned long ebp, esp, eip; + unsigned long stack_page; + int count = 0; + + stack_page = (unsigned long)p; + esp = p->tss.esp; + if (!stack_page || esp < stack_page || esp >= 8188+stack_page) + return 0; + /* include/asm-i386/system.h:switch_to() pushes ebp last. */ + ebp = *(unsigned long *) esp; + do { + if (ebp < stack_page || ebp >= 8188+stack_page) + return 0; + eip = *(unsigned long *) (ebp+4); + if (eip < first_sched || eip >= last_sched) + return eip; + ebp = *(unsigned long *) ebp; + } while (count++ < 16); + } +#elif defined(__alpha__) + /* + * This one depends on the frame size of schedule(). Do a + * "disass schedule" in gdb to find the frame size. Also, the + * code assumes that sleep_on() follows immediately after + * interruptible_sleep_on() and that add_timer() follows + * immediately after interruptible_sleep(). Ugly, isn't it? + * Maybe adding a wchan field to task_struct would be better, + * after all... + */ + { + unsigned long schedule_frame; + unsigned long pc; + + pc = thread_saved_pc(&p->tss); + if (pc >= first_sched && pc < last_sched) { + schedule_frame = ((unsigned long *)p->tss.ksp)[6]; + return ((unsigned long *)schedule_frame)[12]; + } + return pc; + } +#elif defined(__mc68000__) + { + unsigned long fp, pc; + unsigned long stack_page; + int count = 0; + + stack_page = (unsigned long)p; + fp = ((struct switch_stack *)p->tss.ksp)->a6; + do { + if (fp < stack_page+sizeof(struct task_struct) || + fp >= 8184+stack_page) + return 0; + pc = ((unsigned long *)fp)[1]; + /* FIXME: This depends on the order of these functions. */ + if (pc < first_sched || pc >= last_sched) + return pc; + fp = *(unsigned long *) fp; + } while (count++ < 16); + } +#elif defined(__powerpc__) + return (p->tss.wchan); +#elif defined (CONFIG_ARM) + { + unsigned long fp, lr; + unsigned long stack_page; + int count = 0; + + stack_page = 4096 + (unsigned long)p; + fp = get_css_fp (&p->tss); + do { + if (fp < stack_page || fp > 4092+stack_page) + return 0; + lr = pc_pointer (((unsigned long *)fp)[-1]); + if (lr < first_sched || lr > last_sched) + return lr; + fp = *(unsigned long *) (fp - 12); + } while (count ++ < 16); + } +#elif defined (__sparc__) + { + unsigned long pc, fp, bias = 0; + unsigned long task_base = (unsigned long) p; + struct reg_window *rw; + int count = 0; + +#ifdef __sparc_v9__ + bias = STACK_BIAS; +#endif + fp = p->tss.ksp + bias; + do { + /* Bogus frame pointer? */ + if (fp < (task_base + sizeof(struct task_struct)) || + fp >= (task_base + (2 * PAGE_SIZE))) + break; + rw = (struct reg_window *) fp; + pc = rw->ins[7]; + if (pc < first_sched || pc >= last_sched) + return pc; + fp = rw->ins[6] + bias; + } while (++count < 16); + } +#endif + return 0; +} + +#if defined(__i386__) +# define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1019]) +# define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022]) +#elif defined(__alpha__) + /* + * See arch/alpha/kernel/ptrace.c for details. + */ +# define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \ + + (long)&((struct pt_regs *)0)->reg) +# define KSTK_EIP(tsk) \ + (*(unsigned long *)(PT_REG(pc) + PAGE_SIZE + (unsigned long)(tsk))) +# define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp) +#elif defined(CONFIG_ARM) +# define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022]) +# define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1020]) +#elif defined(__mc68000__) +#define KSTK_EIP(tsk) \ + ({ \ + unsigned long eip = 0; \ + if ((tsk)->tss.esp0 > PAGE_SIZE && \ + MAP_NR((tsk)->tss.esp0) < max_mapnr) \ + eip = ((struct pt_regs *) (tsk)->tss.esp0)->pc; \ + eip; }) +#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp) +#elif defined(__powerpc__) +#define KSTK_EIP(tsk) ((tsk)->tss.regs->nip) +#define KSTK_ESP(tsk) ((tsk)->tss.regs->gpr[1]) +#elif defined (__sparc_v9__) +# define KSTK_EIP(tsk) ((tsk)->tss.kregs->tpc) +# define KSTK_ESP(tsk) ((tsk)->tss.kregs->u_regs[UREG_FP]) +#elif defined(__sparc__) +# define KSTK_EIP(tsk) ((tsk)->tss.kregs->pc) +# define KSTK_ESP(tsk) ((tsk)->tss.kregs->u_regs[UREG_FP]) +#endif +; + +static inline void +task_mem (struct task_struct *p, libgtop_proc_segment_t *proc_segment) +{ + struct mm_struct * mm = p->mm; + + if (mm && mm != &init_mm) { + struct vm_area_struct * vma = mm->mmap; + unsigned long data = 0, stack = 0; + unsigned long exec = 0, lib = 0; + unsigned long vsize = 0; + + for (vma = mm->mmap; vma; vma = vma->vm_next) { + unsigned long len = (vma->vm_end - vma->vm_start) >> 10; + vsize += len; + if (!vma->vm_file) { + data += len; + if (vma->vm_flags & VM_GROWSDOWN) + stack += len; + continue; + } + if (vma->vm_flags & VM_WRITE) + continue; + if (vma->vm_flags & VM_EXEC) { + exec += len; + if (vma->vm_flags & VM_EXECUTABLE) + continue; + lib += len; + } + } + + proc_segment->vsize = vsize; + proc_segment->data = data; + proc_segment->stack = stack; + proc_segment->exec = exec; + proc_segment->lib = lib; + } +} + +static inline void +statm_pte_range (pmd_t * pmd, unsigned long address, unsigned long size, + int * pages, int * shared, int * dirty, int * total) +{ + pte_t * pte; + unsigned long end; + + if (pmd_none(*pmd)) + return; + if (pmd_bad(*pmd)) { + printk("statm_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd)); + pmd_clear(pmd); + return; + } + pte = pte_offset(pmd, address); + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + pte_t page = *pte; + + address += PAGE_SIZE; + pte++; + if (pte_none(page)) + continue; + ++*total; + if (!pte_present(page)) + continue; + ++*pages; + if (pte_dirty(page)) + ++*dirty; + if (MAP_NR(pte_page(page)) >= max_mapnr) + continue; + if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) > 1) + ++*shared; + } while (address < end); +} + +static inline void +statm_pmd_range (pgd_t * pgd, unsigned long address, unsigned long size, + int * pages, int * shared, int * dirty, int * total) +{ + pmd_t * pmd; + unsigned long end; + + if (pgd_none(*pgd)) + return; + if (pgd_bad(*pgd)) { + printk("statm_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd)); + pgd_clear(pgd); + return; + } + pmd = pmd_offset(pgd, address); + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + statm_pte_range (pmd, address, end - address, pages, + shared, dirty, total); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); +} + +static void +statm_pgd_range (pgd_t * pgd, unsigned long address, unsigned long end, + int * pages, int * shared, int * dirty, int * total) +{ + while (address < end) { + statm_pmd_range (pgd, address, end - address, pages, + shared, dirty, total); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + pgd++; + } +} + +static void +get_statm (struct task_struct *tsk, libgtop_proc_mem_t *proc_mem) +{ + int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0; + unsigned long data=0, stack=0, exec=0, lib=0; + unsigned long vsize = 0; + + if (tsk->mm && tsk->mm != &init_mm) { + struct vm_area_struct * vma = tsk->mm->mmap; + + while (vma) { + unsigned long len = (vma->vm_end - vma->vm_start) >> 10; + pgd_t *pgd = pgd_offset(tsk->mm, vma->vm_start); + int pages = 0, shared = 0, dirty = 0, total = 0; + + vsize += len; + + statm_pgd_range (pgd, vma->vm_start, vma->vm_end, + &pages, &shared, &dirty, &total); + resident += pages; + share += shared; + dt += dirty; + size += total; + if (vma->vm_flags & VM_EXECUTABLE) + trs += pages; /* text */ + else if (vma->vm_flags & VM_GROWSDOWN) + drs += pages; /* stack */ + else if (vma->vm_end > 0x60000000) + lrs += pages; /* library */ + else + drs += pages; + + if (!vma->vm_file) { + data += len; + if (vma->vm_flags & VM_GROWSDOWN) + stack += len; + vma = vma->vm_next; + continue; + } + if (vma->vm_flags & VM_WRITE) { + vma = vma->vm_next; + continue; + } + if (vma->vm_flags & VM_EXEC) { + exec += len; + if (vma->vm_flags & VM_EXECUTABLE) { + vma = vma->vm_next; + continue; + } + lib += len; + } + + vma = vma->vm_next; + } + } + + proc_mem->segment.vsize = vsize; + proc_mem->segment.data = data; + proc_mem->segment.stack = stack; + proc_mem->segment.exec = exec; + proc_mem->segment.lib = lib; + + proc_mem->size = size; + proc_mem->resident = resident; + proc_mem->share = share; + proc_mem->trs = trs; + proc_mem->lrs = lrs; + proc_mem->drs = drs; + proc_mem->dt = dt; +} + +static void +collect_sigign_sigcatch (struct task_struct *p, sigset_t *ign, + sigset_t *catch) +{ + struct k_sigaction *k; + int i; + + sigemptyset(ign); + sigemptyset(catch); + + if (p->sig) { + k = p->sig->action; + for (i = 1; i <= _NSIG; ++i, ++k) { + if (k->sa.sa_handler == SIG_IGN) + sigaddset(ign, i); + else if (k->sa.sa_handler != SIG_DFL) + sigaddset(catch, i); + } + } +} + +static void +task_sig (struct task_struct *p, libgtop_proc_signal_t *proc_signal) +{ + sigset_t ignore, catch; + int i, nsig; + + if (_NSIG_WORDS > LIBGTOP_NSIG) + nsig = LIBGTOP_NSIG; + else + nsig = _NSIG_WORDS; + + collect_sigign_sigcatch (p, &ignore, &catch); + + for (i = 0; i < nsig; i++) { + proc_signal->signal [i] = p->signal.sig [i]; + proc_signal->blocked [i] = p->blocked.sig [i]; + proc_signal->ignore [i] = ignore.sig [i]; + proc_signal->catch [i] = catch.sig [i]; + } +} + +static int +libgtop_sysctl (ctl_table *table, int nlen, int *name) +{ + extern unsigned long total_forks; + int index, tindex, tty, which, arg; + libgtop_stat_t *lstat; + libgtop_mem_t *mem; + libgtop_swap_t *swap; + libgtop_proclist_t *proclist; + struct task_struct *tsk = NULL; + struct sysinfo i; + + switch (table->ctl_name) { + case LIBGTOP_STAT: + lstat = table->data; + lstat->cpu.total = jiffies; + lstat->cpu.user = kstat.cpu_user; + lstat->cpu.nice = kstat.cpu_nice; + lstat->cpu.sys = kstat.cpu_system; + lstat->cpu.idle = jiffies*smp_num_cpus - + (lstat->cpu.user + lstat->cpu.nice + lstat->cpu.sys); +#ifdef __SMP__ + for (i = 0; i < smp_num_cpus; i++) { + lstat->xcpu[i].user = kstat.per_cpu_user[cpu_logical_map(i)]; + lstat->xcpu[i].nice = kstat.per_cpu_nice[cpu_logical_map(i)]; + lstat->xcpu[i].sys = kstat.per_cpu_system[cpu_logical_map(i)]; + lstat->xcpu[i].idle = jiffies - + (lstat->xcpu[i].user + lstat->xcpu[i].nice + + lstat->xcpu[i].sys); + } + + lstat->ncpu = smp_num_cpus; +#else + lstat->ncpu = 0; +#endif + + lstat->frequency = HZ; + + lstat->loadavg [0] = (double) avenrun [0] / (1 << FSHIFT); + lstat->loadavg [1] = (double) avenrun [1] / (1 << FSHIFT); + lstat->loadavg [2] = (double) avenrun [2] / (1 << FSHIFT); + + lstat->pgpgin = kstat.pgpgin; + lstat->pgpgout = kstat.pgpgout; + lstat->pswpin = kstat.pswpin; + lstat->pswpout = kstat.pswpout; + + lstat->context_swtch = kstat.context_swtch; + lstat->boot_time = xtime.tv_sec - jiffies / HZ; + lstat->total_forks = total_forks; + break; + case LIBGTOP_MEM: + if (jiffies - libgtop_mem_timestamp < libgtop_update_expensive) + return 0; + libgtop_mem_timestamp = jiffies; + + mem = table->data; + si_meminfo (&i); + + mem->totalram = i.totalram; + mem->freeram = i.freeram; + mem->sharedram = i.sharedram; + mem->bufferram = i.bufferram; +#if 0 + mem->cachedram = page_cache_size * PAGE_SIZE; +#endif + return 0; + case LIBGTOP_SWAP: + if (jiffies - libgtop_swap_timestamp < libgtop_update_expensive) + return 0; + libgtop_swap_timestamp = jiffies; + + swap = table->data; + si_swapinfo (&i); + + swap->totalswap = i.totalswap; + swap->freeswap = i.freeswap; + return 0; + case LIBGTOP_PROCLIST: + proclist = table->data; + + if (nlen == 1) { + which = 0; + arg = 0; + } else if (nlen == 2) { + which = name [1]; + arg = 0; + } else if (nlen == 3) { + which = name [1]; + arg = name [2]; + } else { + return -EINVAL; + } + + tsk = task [0]; + read_lock (&tasklist_lock); + for (index = tindex = 0; (index <= nr_tasks) && tsk->next_task; + index++, tsk = tsk->next_task) { + if (tsk->pid == 0) continue; + switch (which & LIBGTOP_PROCLIST_MASK) { + case LIBGTOP_PROCLIST_PID: + if (tsk->pid != arg) continue; + break; + case LIBGTOP_PROCLIST_PGRP: + if (tsk->pgrp != arg) continue; + break; + case LIBGTOP_PROCLIST_SESSION: + if (tsk->session != arg) continue; + break; + case LIBGTOP_PROCLIST_TTY: + tty = tsk->tty ? + kdev_t_to_nr (tsk->tty->device) : 0; + if (tty != arg) continue; + break; + case LIBGTOP_PROCLIST_UID: + if (tsk->uid != arg) continue; + break; + case LIBGTOP_PROCLIST_RUID: + if (tsk->euid != arg) continue; + break; + } + + if ((which & LIBGTOP_EXCLUDE_IDLE) && (tsk->state != 0)) + continue; + + if ((which & LIBGTOP_EXCLUDE_NOTTY) && (tsk->tty == NULL)) + continue; + + proclist->pids [tindex++] = tsk->pid; + } + + proclist->count = tindex; + proclist->nr_running = nr_running; + proclist->last_pid = last_pid; + proclist->nr_tasks = tindex; + read_unlock(&tasklist_lock); + return 0; + default: + return -EINVAL; + } + + return 0; +} + +static int +libgtop_sysctl_proc (ctl_table *table, int nlen, int *name, + struct task_struct *tsk) +{ + libgtop_proc_state_t *proc_state; + libgtop_proc_kernel_t *proc_kernel; + libgtop_proc_segment_t *proc_segment; + libgtop_proc_signal_t *proc_signal; + libgtop_proc_mem_t *proc_mem; + int i; + + switch (table->ctl_name) { + case LIBGTOP_PROC_STATE: + proc_state = table->data; + memset (proc_state, 0, sizeof (libgtop_proc_state_t)); + + proc_state->uid = tsk->uid; + proc_state->gid = tsk->gid; + proc_state->flags = tsk->flags; + memcpy (proc_state->comm, tsk->comm, sizeof (proc_state->comm)); + proc_state->uid = tsk->uid; + proc_state->euid = tsk->euid; + proc_state->suid = tsk->suid; + proc_state->fsuid = tsk->fsuid; + + proc_state->gid = tsk->gid; + proc_state->egid = tsk->egid; + proc_state->sgid = tsk->sgid; + proc_state->fsgid = tsk->fsgid; + + proc_state->pid = tsk->pid; + proc_state->pgrp = tsk->pgrp; + proc_state->ppid = tsk->p_pptr->pid; + + proc_state->session = tsk->session; + proc_state->tty = tsk->tty ? + kdev_t_to_nr (tsk->tty->device) : 0; + proc_state->tpgid = tsk->tty ? tsk->tty->pgrp : -1; + + proc_state->priority = tsk->priority; + proc_state->counter = tsk->counter; + proc_state->def_priority = DEF_PRIORITY; + + proc_state->utime = tsk->times.tms_utime; + proc_state->stime = tsk->times.tms_stime; + proc_state->cutime = tsk->times.tms_cutime; + proc_state->cstime = tsk->times.tms_cstime; + + proc_state->start_time = tsk->start_time; + +#ifdef __SMP__ + for (i = 0; i < NR_CPUS; i++) { + proc_state->per_cpu_utime [i] = tsk->per_cpu_utime [i]; + proc_state->per_cpu_stime [i] = tsk->per_cpu_stime [i]; + } +#endif + + proc_state->has_cpu = tsk->has_cpu; + proc_state->processor = tsk->processor; + proc_state->last_processor = tsk->last_processor; + + proc_state->policy = tsk->policy; + proc_state->rt_priority = tsk->rt_priority; + + proc_state->it_real_value = tsk->it_real_value; + proc_state->it_prof_value = tsk->it_prof_value; + proc_state->it_virt_value = tsk->it_virt_value; + proc_state->it_real_incr = tsk->it_real_incr; + proc_state->it_prof_incr = tsk->it_prof_incr; + proc_state->it_virt_incr = tsk->it_virt_incr; + + proc_state->min_flt = tsk->min_flt; + proc_state->cmin_flt = tsk->cmin_flt; + proc_state->maj_flt = tsk->maj_flt; + proc_state->cmaj_flt = tsk->cmaj_flt; + + proc_state->nswap = tsk->nswap; + proc_state->cnswap = tsk->cnswap; + + proc_state->kesp = KSTK_ESP(tsk); + proc_state->keip = KSTK_EIP(tsk); + + if (tsk->mm && tsk->mm != &init_mm) { + proc_state->context = tsk->mm->context; + proc_state->start_code = tsk->mm->start_code; + proc_state->end_code = tsk->mm->end_code; + proc_state->start_data = tsk->mm-> start_data; + proc_state->end_data = tsk->mm->end_data; + proc_state->start_brk = tsk->mm->start_brk; + proc_state->brk = tsk->mm->brk; + proc_state->start_stack = tsk->mm->start_stack; + proc_state->start_mmap = tsk->mm->mmap ? + tsk->mm->mmap->vm_start : 0; + proc_state->arg_start = tsk->mm->arg_start; + proc_state->arg_end = tsk->mm->arg_end; + proc_state->env_start = tsk->mm->env_start; + proc_state->env_end = tsk->mm->env_end; + proc_state->rss = tsk->mm->rss << PAGE_SHIFT; + proc_state->total_vm = tsk->mm->total_vm; + proc_state->locked_vm = tsk->mm->locked_vm; + + } + proc_state->rlim = tsk->rlim ? tsk->rlim[RLIMIT_RSS].rlim_cur : 0; + + proc_state->ngroups = tsk->ngroups; + for (i = 0; i < min (tsk->ngroups, LIBGTOP_MAX_GROUPS); i++) + proc_state->groups [i] = tsk->groups [i]; + + if (tsk->state & TASK_INTERRUPTIBLE) + proc_state->state |= LIBGTOP_TASK_INTERRUPTIBLE; + if (tsk->state & TASK_UNINTERRUPTIBLE) + proc_state->state |= LIBGTOP_TASK_UNINTERRUPTIBLE; + if (tsk->state & TASK_ZOMBIE) + proc_state->state |= LIBGTOP_TASK_ZOMBIE; + if (tsk->state & TASK_STOPPED) + proc_state->state |= LIBGTOP_TASK_STOPPED; + if (tsk->state & TASK_SWAPPING) + proc_state->state |= LIBGTOP_TASK_SWAPPING; + + if (!(tsk->state & (TASK_RUNNING | TASK_INTERRUPTIBLE | + TASK_UNINTERRUPTIBLE | TASK_ZOMBIE | + TASK_STOPPED | TASK_SWAPPING))) + proc_state->state |= LIBGTOP_TASK_RUNNING; + break; + case LIBGTOP_PROC_KERNEL: + proc_kernel = table->data; + memset (proc_kernel, 0, sizeof (libgtop_proc_kernel_t)); + + proc_kernel->wchan = get_wchan (tsk); + break; + case LIBGTOP_PROC_SEGMENT: + proc_segment = table->data; + memset (proc_segment, 0, sizeof (libgtop_proc_segment_t)); + + task_mem (tsk, proc_segment); + break; + case LIBGTOP_PROC_MEM: + proc_mem = table->data; + memset (proc_mem, 0, sizeof (libgtop_proc_mem_t)); + + get_statm (tsk, proc_mem); + /* Use LIBGTOP_PROC_STAT if you only want rss and rlim. */ + proc_mem->rss = tsk->mm->rss << PAGE_SHIFT; + proc_mem->rlim = tsk->rlim ? tsk->rlim[RLIMIT_RSS].rlim_cur : 0; + break; + case LIBGTOP_PROC_SIGNAL: + proc_signal = table->data; + memset (proc_signal, 0, sizeof (libgtop_proc_signal_t)); + + task_sig (tsk, proc_signal); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int +system_ctl_handler (ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, void *newval, + size_t newlen, void **context) +{ + int ret, len, len_name; + + if (!table->data || !table->maxlen) + return -ENOTDIR; + + if (!oldval || !oldlenp || get_user(len, oldlenp)) + return -EFAULT; + + if (!name || !nlen || get_user(len_name, name)) + return -EFAULT; + + if (len != table->maxlen) + return -EFAULT; + + ret = libgtop_sysctl (table, nlen, name); + if (ret) return ret; + + if(copy_to_user(oldval, table->data, len)) + return -EFAULT; + + return 1; +} + +static int +proc_ctl_handler (ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, void *newval, + size_t newlen, void **context) +{ + struct task_struct *tsk = NULL; + int ret, len, len_name; + + if (!table->data || !table->maxlen) + return -ENOTDIR; + + if (!oldval || !oldlenp || get_user(len, oldlenp)) + return -EFAULT; + + if (!name || !nlen || get_user(len_name, name)) + return -EFAULT; + + if (len != table->maxlen) + return -EFAULT; + + if (nlen != 2) + return -EFAULT; + + read_lock (&tasklist_lock); + tsk = find_task_by_pid (name [1]); + /* FIXME!! This should be done after the last use */ + read_unlock(&tasklist_lock); + + if (tsk == NULL) + return -ESRCH; + + ret = libgtop_sysctl_proc (table, nlen, name, tsk); + if (ret) return ret; + + if(copy_to_user(oldval, table->data, len)) + return -EFAULT; + + return 1; +} + +static unsigned long +get_phys_addr (struct task_struct * p, unsigned long ptr) +{ + pgd_t *page_dir; + pmd_t *page_middle; + pte_t pte; + + if (!p || !p->mm || ptr >= TASK_SIZE) + return 0; + /* Check for NULL pgd .. shouldn't happen! */ + if (!p->mm->pgd) { + printk("get_phys_addr: pid %d has NULL pgd!\n", p->pid); + return 0; + } + + page_dir = pgd_offset(p->mm,ptr); + if (pgd_none(*page_dir)) + return 0; + if (pgd_bad(*page_dir)) { + printk("bad page directory entry %08lx\n", pgd_val(*page_dir)); + pgd_clear(page_dir); + return 0; + } + page_middle = pmd_offset(page_dir,ptr); + if (pmd_none(*page_middle)) + return 0; + if (pmd_bad(*page_middle)) { + printk("bad page middle entry %08lx\n", pmd_val(*page_middle)); + pmd_clear(page_middle); + return 0; + } + pte = *pte_offset(page_middle,ptr); + if (!pte_present(pte)) + return 0; + return pte_page(pte) + (ptr & ~PAGE_MASK); +} + +static int +get_array (struct task_struct *p, unsigned long start, unsigned long end, + char * buffer) +{ + unsigned long addr; + int size = 0, result = 0; + char c; + + if (start >= end) + return result; + for (;;) { + addr = get_phys_addr (p, start); + if (!addr) + return result; + do { + c = *(char *) addr; + if (!c) + result = size; + if (size < PAGE_SIZE) + buffer[size++] = c; + else + return result; + addr++; + start++; + if (!c && start >= end) + return result; + } while (addr & ~PAGE_MASK); + } + + return result; +} + +static int +proc_args_ctl_handler (ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, void *newval, + size_t newlen, void **context) +{ + struct task_struct *tsk = NULL; + int ret, len, len_name; + unsigned long page; + + if (!oldval || !oldlenp || get_user (len, oldlenp)) + return -EFAULT; + + if (!name || !nlen || get_user (len_name, name)) + return -EFAULT; + + if (nlen != 2) + return -EFAULT; + + read_lock (&tasklist_lock); + tsk = find_task_by_pid (name [1]); + /* FIXME!! This should be done after the last use */ + read_unlock (&tasklist_lock); + + if (!tsk || !tsk->mm) + return -ESRCH; + + if (!(page = __get_free_page (GFP_KERNEL))) + return -ENOMEM; + + ret = get_array (tsk, tsk->mm->arg_start, + tsk->mm->arg_end, (char *) page); + if (ret < 0) { + free_page (page); + return ret; + } + + if (ret < len) + len = ret; + + if (put_user (len, oldlenp)) + goto err_fault_free_page; + + if (copy_to_user (oldval, (void *) page, len)) + goto err_fault_free_page; + + free_page (page); + return 1; + + err_fault_free_page: + free_page (page); + return -EFAULT; +} + +static int +proc_maps_ctl_handler (ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, void *newval, + size_t newlen, void **context) +{ + struct task_struct *p = NULL; + struct vm_area_struct * map, * next; + int i, len, len_name, retval = -EINVAL; + libgtop_proc_maps_t *proc_maps; + size_t count, wrote = 0; + loff_t lineno = 0; + int volatile_task; + + if (!oldlenp || get_user (len, oldlenp)) + return -EFAULT; + + if (!name || !nlen || get_user (len_name, name)) + return -EFAULT; + + if (nlen != 2) + return -EFAULT; + + read_lock (&tasklist_lock); + p = find_task_by_pid (name [1]); + /* FIXME!! This should be done after the last use */ + read_unlock (&tasklist_lock); + + if (!p || !p->mm) + return -ESRCH; + + if (len % sizeof (libgtop_proc_maps_t)) + return -EINVAL; + + count = len / sizeof (libgtop_proc_maps_t); + + if (!(proc_maps = kmalloc (sizeof (libgtop_proc_maps_t), GFP_KERNEL))) + return -ENOMEM; + + if (!p->mm || p->mm == &init_mm) + goto write_len_out; + + /* Check whether the mmaps could change if we sleep */ + volatile_task = (p != current || atomic_read (&p->mm->count) > 1); + + if (count == 0) { + /* Only get total count. */ + for (map = p->mm->mmap, i = 0; map; map = map->vm_next, i++) + continue; + wrote = i; + goto write_len_success; + } + + /* quickly go to line lineno */ + for (map = p->mm->mmap, i = 0; map && (i < lineno); + map = map->vm_next, i++) + continue; + + for ( ; map; map = next) { + memset (proc_maps, 0, sizeof (libgtop_proc_maps_t)); + + /* + * Get the next vma now (but it won't be used if we sleep). + */ + next = map->vm_next; + + proc_maps->header.start = map->vm_start; + proc_maps->header.end = map->vm_end; + proc_maps->header.offset = map->vm_offset; + + proc_maps->header.perm = map->vm_flags; + + if (map->vm_file != NULL) { + char *line = d_path (map->vm_file->f_dentry, proc_maps->filename, + LIBGTOP_MAP_PATH_LEN); + + proc_maps->filename [LIBGTOP_MAP_PATH_LEN-1] = '\0'; + proc_maps->header.filename_offset = line - proc_maps->filename; + + proc_maps->header.device = + map->vm_file->f_dentry->d_inode->i_dev; + proc_maps->header.inode = + map->vm_file->f_dentry->d_inode->i_ino; + } + + /* Copy current entry to user space. */ + if (copy_to_user (oldval, proc_maps, sizeof (*proc_maps))) { + retval = -EFAULT; + goto free_page_out; + } + + wrote += sizeof (*proc_maps); + + oldval += sizeof (*proc_maps); + len -= sizeof (*proc_maps); + count--; + + /* If there are no more entries, we don't have to worry about space. */ + if (next == NULL) + goto write_len_success; + + if (len < sizeof (*proc_maps)) { + retval = -EFAULT; + goto write_len_out; + } + + if (count == 0) { + retval = -E2BIG; + goto write_len_out; + } + } + + retval = -ENOSYS; + goto free_page_out; + + return retval; + + write_len_success: + retval = 1; + + write_len_out: + if (put_user (wrote, oldlenp)) { + retval = -EFAULT; + goto free_page_out; + } + + free_page_out: + kfree (proc_maps); + return retval; +} + +#if CONFIG_NET + +static int +proc_net_ctl_handler (ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, void *newval, + size_t newlen, void **context) +{ + int len, len_name, retval = -ENOSYS; + struct net_device_stats *stats; + libgtop_netload_t netload; + struct device *dev; + char *dev_name; + + if (!oldlenp || get_user (len, oldlenp)) + return -EFAULT; + + if (len != sizeof (libgtop_netload_t)) + return -EFAULT; + + if (!name || !nlen || get_user (len_name, name)) + return -EFAULT; + + if (nlen != 1) + return -EFAULT; + + /* Allocate memory for device name. */ + if (newlen > PAGE_SIZE) + return -ENOMEM; + + if (!(dev_name = kmalloc (newlen+1, GFP_KERNEL))) + return -ENOMEM; + + /* Copy device name from user space. */ + if (copy_from_user (dev_name, newval, newlen)) { + retval = -EFAULT; + goto free_name_out; + } + dev_name [newlen] = '\0'; + + dev = dev_get (dev_name); + if (!dev) { + retval = -ENODEV; + goto free_name_out; + } + + if (!dev->get_stats) { + retval = -ENODEV; + goto free_name_out; + } + + stats = dev->get_stats (dev); + + if (!stats) { + retval = -ENODEV; + goto free_name_out; + } + + netload.rx_packets = stats->rx_packets; + netload.tx_packets = stats->tx_packets; + + netload.rx_bytes = stats->rx_bytes; + netload.tx_bytes = stats->tx_bytes; + + netload.rx_errors = stats->rx_errors; + netload.tx_errors = stats->tx_errors; + + netload.rx_dropped = stats->rx_dropped; + netload.tx_dropped = stats->tx_dropped; + + netload.multicast = stats->multicast; + netload.collisions = stats->collisions; + + netload.rx_length_errors = stats->rx_length_errors; + netload.rx_over_errors = stats->rx_over_errors; + netload.rx_crc_errors = stats->rx_crc_errors; + netload.rx_frame_errors = stats->rx_frame_errors; + netload.rx_fifo_errors = stats->rx_fifo_errors; + netload.rx_missed_errors = stats->rx_missed_errors; + + netload.tx_aborted_errors = stats->tx_aborted_errors; + netload.tx_carrier_errors = stats->tx_carrier_errors; + netload.tx_fifo_errors = stats->tx_fifo_errors; + netload.tx_heartbeat_errors = stats->tx_heartbeat_errors; + netload.tx_window_errors = stats->tx_window_errors; + + netload.rx_compressed = stats->rx_compressed; + netload.tx_compressed = stats->tx_compressed; + + if (copy_to_user (oldval, (void *) &netload, len)) { + retval = -EFAULT; + goto free_name_out; + } + + retval = 1; + + free_name_out: + kfree (dev_name); + return retval; +} + +#endif /* CONFIG_NET */ diff --git a/kernel/sysctl/libgtop.h b/kernel/sysctl/libgtop.h new file mode 100644 index 00000000..f43a91c5 --- /dev/null +++ b/kernel/sysctl/libgtop.h @@ -0,0 +1,242 @@ +#ifndef _LINUX_LIBGTOP_H +#define _LINUX_LIBGTOP_H 1 + +#include <linux/tasks.h> + +enum { + LIBGTOP_VERSION = 1, + LIBGTOP_UPDATE_EXPENSIVE, + LIBGTOP_STAT = 101, + LIBGTOP_MEM, + LIBGTOP_SWAP, + LIBGTOP_PROCLIST = 201, + LIBGTOP_PROC_STATE = 211, + LIBGTOP_PROC_KERNEL, + LIBGTOP_PROC_SEGMENT, + LIBGTOP_PROC_MEM, + LIBGTOP_PROC_SIGNAL, + LIBGTOP_PROC_ARGS = 251, + LIBGTOP_PROC_MAPS, + LIBGTOP_NETLOAD = 301 +}; + +enum { + LIBGTOP_PROCLIST_ALL = 0, + LIBGTOP_PROCLIST_PID, + LIBGTOP_PROCLIST_PGRP, + LIBGTOP_PROCLIST_SESSION, + LIBGTOP_PROCLIST_TTY, + LIBGTOP_PROCLIST_UID, + LIBGTOP_PROCLIST_RUID +}; + +#define LIBGTOP_NSIG 4 + +#define LIBGTOP_PROCLIST_MASK 15 +#define LIBGTOP_MAX_GROUPS 32 + +#define LIBGTOP_EXCLUDE_IDLE 0x1000 +#define LIBGTOP_EXCLUDE_SYSTEM 0x2000 +#define LIBGTOP_EXCLUDE_NOTTY 0x4000 + +#define LIBGTOP_TASK_RUNNING 1 +#define LIBGTOP_TASK_INTERRUPTIBLE 2 +#define LIBGTOP_TASK_UNINTERRUPTIBLE 4 +#define LIBGTOP_TASK_ZOMBIE 8 +#define LIBGTOP_TASK_STOPPED 16 +#define LIBGTOP_TASK_SWAPPING 32 + +#define LIBGTOP_VM_READ 0x0001 /* currently active flags */ +#define LIBGTOP_VM_WRITE 0x0002 +#define LIBGTOP_VM_EXEC 0x0004 +#define LIBGTOP_VM_SHARED 0x0008 + +#define LIBGTOP_VM_MAYREAD 0x0010 /* limits for mprotect() etc */ +#define LIBGTOP_VM_MAYWRITE 0x0020 +#define LIBGTOP_VM_MAYEXEC 0x0040 +#define LIBGTOP_VM_MAYSHARE 0x0080 + +#define LIBGTOP_VM_GROWSDOWN 0x0100 /* general info on the segment */ +#define LIBGTOP_VM_GROWSUP 0x0200 +#define LIBGTOP_VM_SHM 0x0400 /* shared memory area, don't swap out */ +#define LIBGTOP_VM_DENYWRITE 0x0800 /* ETXTBSY on write attempts.. */ + +#define LIBGTOP_VM_EXECUTABLE 0x1000 +#define LIBGTOP_VM_LOCKED 0x2000 +#define LIBGTOP_VM_IO 0x4000 /* Memory mapped I/O or similar */ + +#define LIBGTOP_MAP_PATH_LEN (PAGE_SIZE - sizeof (libgtop_proc_maps_header_t)) + +#ifndef min +#define min(a,b) ((a < b) ? a : b) +#endif + +typedef struct libgtop_stat libgtop_stat_t; + +typedef struct libgtop_cpu libgtop_cpu_t; +typedef struct libgtop_mem libgtop_mem_t; +typedef struct libgtop_swap libgtop_swap_t; +typedef struct libgtop_proclist libgtop_proclist_t; + +typedef struct libgtop_proc_state libgtop_proc_state_t; +typedef struct libgtop_proc_kernel libgtop_proc_kernel_t; +typedef struct libgtop_proc_segment libgtop_proc_segment_t; +typedef struct libgtop_proc_mem libgtop_proc_mem_t; +typedef struct libgtop_proc_signal libgtop_proc_signal_t; + +typedef struct libgtop_proc_maps_header libgtop_proc_maps_header_t; +typedef struct libgtop_proc_maps libgtop_proc_maps_t; + +typedef struct libgtop_netload libgtop_netload_t; + +struct libgtop_cpu +{ + unsigned long total; /* Total CPU Time */ + unsigned long user; /* CPU Time in User Mode */ + unsigned long nice; /* CPU Time in User Mode (nice) */ + unsigned long sys; /* CPU Time in System Mode */ + unsigned long idle; /* CPU Time in the Idle Task */ +}; + +struct libgtop_mem +{ + unsigned long totalram; /* Total usable main memory size */ + unsigned long freeram; /* Available memory size */ + unsigned long sharedram; /* Amount of shared memory */ + unsigned long bufferram; /* Memory used by buffers */ + unsigned long cachedram; +}; + +struct libgtop_swap +{ + unsigned long totalswap; /* Total swap space size */ + unsigned long freeswap; /* swap space still available */ +}; + +struct libgtop_proclist +{ + int count; + int nr_running, nr_tasks, last_pid; + unsigned pids [NR_TASKS]; +}; + +struct libgtop_stat +{ + int ncpu; /* Number of CPUs */ + unsigned long frequency; /* Tick frequency (HZ) */ + libgtop_cpu_t cpu; /* CPU statistics */ + libgtop_cpu_t xcpu [NR_CPUS]; /* SMP per-CPU statistics */ + double loadavg [3]; /* Load average */ + unsigned long total_forks; /* Total # of forks */ + unsigned int context_swtch; /* Total # of context switches */ + unsigned long boot_time; /* Boot time (seconds s. epoch) */ + unsigned int pgpgin, pgpgout; /* # of pages paged in/out */ + unsigned int pswpin, pswpout; /* # of swap pgs brought in/out */ +}; + +struct libgtop_proc_state +{ + long state; + unsigned long flags; + char comm [16]; + int uid, euid, suid, fsuid; + int gid, egid, sgid, fsgid; + int pid, pgrp, ppid; + int session; + unsigned int tty; + int tpgid; + long priority, counter, def_priority; + long utime, stime, cutime, cstime, start_time; + long per_cpu_utime [NR_CPUS], per_cpu_stime [NR_CPUS]; + int has_cpu, processor, last_processor; + + unsigned long context; + unsigned long start_code, end_code, start_data, end_data; + unsigned long start_brk, brk, start_stack, start_mmap; + unsigned long arg_start, arg_end, env_start, env_end; + unsigned long rss, rlim, total_vm, locked_vm; + + unsigned long policy, rt_priority; + unsigned long it_real_value, it_prof_value, it_virt_value; + unsigned long it_real_incr, it_prof_incr, it_virt_incr; + + unsigned long keip, kesp; + unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt; + unsigned long nswap, cnswap; + + int ngroups, groups [LIBGTOP_MAX_GROUPS]; +}; + +struct libgtop_proc_kernel +{ + unsigned long wchan; +}; + +struct libgtop_proc_segment +{ + unsigned long vsize, data, exec, stack, lib; +}; + +struct libgtop_proc_mem +{ + libgtop_proc_segment_t segment; + int size, resident, share, trs, lrs, drs, dt; + unsigned long rss, rlim; +}; + +struct libgtop_proc_signal +{ + unsigned long signal [LIBGTOP_NSIG]; + unsigned long blocked [LIBGTOP_NSIG]; + unsigned long ignore [LIBGTOP_NSIG]; + unsigned long catch [LIBGTOP_NSIG]; +}; + +struct libgtop_proc_maps_header +{ + unsigned long start, end, offset, perm; + off_t filename_offset; + ino_t inode; + dev_t device; +} __attribute__ ((aligned (64))); + +struct libgtop_proc_maps +{ + libgtop_proc_maps_header_t header; + char filename [LIBGTOP_MAP_PATH_LEN]; +}; + +struct libgtop_netload +{ + unsigned long rx_packets; /* total packets received */ + unsigned long tx_packets; /* total packets transmitted */ + unsigned long rx_bytes; /* total bytes received */ + unsigned long tx_bytes; /* total bytes transmitted */ + unsigned long rx_errors; /* bad packets received */ + unsigned long tx_errors; /* packet transmit problems */ + unsigned long rx_dropped; /* no space in linux buffers */ + unsigned long tx_dropped; /* no space available in linux */ + unsigned long multicast; /* multicast packets received */ + unsigned long collisions; + + /* detailed rx_errors: */ + unsigned long rx_length_errors; + unsigned long rx_over_errors; /* receiver ring buff overflow */ + unsigned long rx_crc_errors; /* recved pkt with crc error */ + unsigned long rx_frame_errors; /* recv'd frame alignment error */ + unsigned long rx_fifo_errors; /* recv'r fifo overrun */ + unsigned long rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + unsigned long tx_aborted_errors; + unsigned long tx_carrier_errors; + unsigned long tx_fifo_errors; + unsigned long tx_heartbeat_errors; + unsigned long tx_window_errors; + + /* for cslip etc */ + unsigned long rx_compressed; + unsigned long tx_compressed; +}; + +#endif diff --git a/kernel/sysctl/libgtop_syms.c b/kernel/sysctl/libgtop_syms.c new file mode 100644 index 00000000..ddffc3f7 --- /dev/null +++ b/kernel/sysctl/libgtop_syms.c @@ -0,0 +1,30 @@ +/* + * linux/libgtop/libgtop_syms.c + * Copyright (C) 1999 Martin Baulig + */ + +#include <linux/config.h> +#include <linux/module.h> + +#include <linux/sched.h> + +#include <linux/mm.h> +#include <linux/pagemap.h> +#include <linux/swap.h> + +extern unsigned long total_forks; + +EXPORT_SYMBOL(task); +EXPORT_SYMBOL(init_mm); +EXPORT_SYMBOL(pidhash); +EXPORT_SYMBOL(avenrun); +EXPORT_SYMBOL(nr_running); +EXPORT_SYMBOL(nr_tasks); +EXPORT_SYMBOL(last_pid); +EXPORT_SYMBOL(total_forks); +EXPORT_SYMBOL(si_swapinfo); + +extern void scheduling_functions_start_here(void); +extern void scheduling_functions_end_here(void); +EXPORT_SYMBOL(scheduling_functions_start_here); +EXPORT_SYMBOL(scheduling_functions_end_here); diff --git a/kernel/sysctl/main.c b/kernel/sysctl/main.c new file mode 100644 index 00000000..6d391eb4 --- /dev/null +++ b/kernel/sysctl/main.c @@ -0,0 +1,4 @@ +/* + * linux/libgtop/main.c + * Copyright (C) 1999 Martin Baulig + */ diff --git a/kernel/sysctl/patch-2.2.1 b/kernel/sysctl/patch-2.2.1 new file mode 100644 index 00000000..1781b921 --- /dev/null +++ b/kernel/sysctl/patch-2.2.1 @@ -0,0 +1,81 @@ +diff -ru linux-2.2.1/Makefile hacker/Makefile +--- linux-2.2.1/Makefile Sun Jan 31 22:45:42 1999 ++++ hacker/Makefile Sun Mar 21 16:10:41 1999 +@@ -109,6 +109,7 @@ + DRIVERS =drivers/block/block.a \ + drivers/char/char.a \ + drivers/misc/misc.a ++EXTRAS = + LIBS =$(TOPDIR)/lib/lib.a + SUBDIRS =kernel drivers mm fs net ipc lib + +@@ -186,6 +187,11 @@ + DRIVERS := $(DRIVERS) drivers/net/irda/irda_drivers.a + endif + ++ifdef CONFIG_LIBGTOP ++SUBDIRS := $(SUBDIRS) libgtop ++EXTRAS := $(EXTRAS) libgtop/kernel.o ++endif ++ + include arch/$(ARCH)/Makefile + + .S.s: +@@ -206,6 +212,7 @@ + $(FILESYSTEMS) \ + $(NETWORKS) \ + $(DRIVERS) \ ++ $(EXTRAS) \ + $(LIBS) \ + --end-group \ + -o vmlinux +diff -ru linux-2.2.1/arch/i386/config.in hacker/arch/i386/config.in +--- linux-2.2.1/arch/i386/config.in Sun Jan 31 22:25:25 1999 ++++ hacker/arch/i386/config.in Sat Mar 20 18:26:18 1999 +@@ -84,6 +84,9 @@ + bool 'System V IPC' CONFIG_SYSVIPC + bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT + bool 'Sysctl support' CONFIG_SYSCTL ++if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ tristate 'LibGTop support' CONFIG_LIBGTOP ++fi + tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT + tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF + tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +diff -ru linux-2.2.1/include/linux/sysctl.h hacker/include/linux/sysctl.h +--- linux-2.2.1/include/linux/sysctl.h Sun Jan 31 22:24:14 1999 ++++ hacker/include/linux/sysctl.h Sat Mar 20 19:12:54 1999 +@@ -56,7 +56,8 @@ + CTL_PROC=4, /* Process info */ + CTL_FS=5, /* Filesystems */ + CTL_DEBUG=6, /* Debugging */ +- CTL_DEV=7 /* Devices */ ++ CTL_DEV=7, /* Devices */ ++ CTL_LIBGTOP=408 /* LibGTop */ + }; + + +diff -ru linux-2.2.1/kernel/sysctl.c hacker/kernel/sysctl.c +--- linux-2.2.1/kernel/sysctl.c Sun Jan 31 22:24:43 1999 ++++ hacker/kernel/sysctl.c Sat Mar 20 19:24:34 1999 +@@ -82,7 +82,9 @@ + static ctl_table fs_table[]; + static ctl_table debug_table[]; + static ctl_table dev_table[]; +- ++#ifdef CONFIG_LIBGTOP ++extern ctl_table libgtop_table[]; ++#endif + + /* /proc declarations: */ + +@@ -148,6 +150,9 @@ + {CTL_FS, "fs", NULL, 0, 0555, fs_table}, + {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table}, + {CTL_DEV, "dev", NULL, 0, 0555, dev_table}, ++#ifdef CONFIG_LIBGTOP ++ {CTL_LIBGTOP, "libgtop", NULL, 0, 0555, libgtop_table}, ++#endif + {0} + }; + |