summaryrefslogtreecommitdiffstats
path: root/fs/proc
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-01-29 01:41:54 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-01-29 01:41:54 +0000
commitf969d69ba9f952e5bdd38278e25e26a3e4a61a70 (patch)
treeb3530d803df59d726afaabebc6626987dee1ca05 /fs/proc
parenta10ce7ef2066b455d69187643ddf2073bfc4db24 (diff)
Merge with 2.3.27.
Diffstat (limited to 'fs/proc')
-rw-r--r--fs/proc/Makefile4
-rw-r--r--fs/proc/array.c1166
-rw-r--r--fs/proc/base.c1097
-rw-r--r--fs/proc/fd.c199
-rw-r--r--fs/proc/generic.c27
-rw-r--r--fs/proc/inode-alloc.txt46
-rw-r--r--fs/proc/inode.c199
-rw-r--r--fs/proc/kcore.c388
-rw-r--r--fs/proc/link.c205
-rw-r--r--fs/proc/mem.c354
-rw-r--r--fs/proc/net.c124
-rw-r--r--fs/proc/proc_misc.c692
-rw-r--r--fs/proc/procfs_syms.c19
-rw-r--r--fs/proc/root.c585
-rw-r--r--fs/proc/scsi.c219
-rw-r--r--fs/proc/sysvipc.c141
16 files changed, 2207 insertions, 3258 deletions
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index 8a5286fa5..8ff6cd522 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -8,8 +8,8 @@
# Note 2! The CFLAGS definitions are now in the main makefile.
O_TARGET := proc.o
-O_OBJS := inode.o root.o base.o generic.o mem.o link.o fd.o array.o \
- kmsg.o scsi.o proc_tty.o sysvipc.o
+O_OBJS := inode.o root.o base.o generic.o array.o \
+ kmsg.o proc_tty.o proc_misc.o kcore.o
ifdef CONFIG_OMIRR
O_OBJS := $(O_OBJS) omirr.o
endif
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 249abd8cd..181cc4e62 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -46,6 +46,10 @@
*
* Gerhard Wichert : added BIGMEM support
* Siemens AG <Gerhard.Wichert@pdb.siemens.de>
+ *
+ * Al Viro & Jeff Garzik : moved most of the thing into base.c and
+ * : proc_misc.c. The rest may eventually go into
+ * : base.c too.
*/
#include <linux/types.h>
@@ -54,8 +58,6 @@
#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>
@@ -67,663 +69,12 @@
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/signal.h>
+#include <linux/highmem.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
-
-#define LOAD_INT(x) ((x) >> FSHIFT)
-#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
-
-#ifdef CONFIG_DEBUG_MALLOC
-int get_malloc(char * buffer);
-#endif
-
-
-static int open_kcore(struct inode * inode, struct file * filp)
-{
- return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
-}
-
-static ssize_t read_core(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- unsigned long p = *ppos, memsize;
- ssize_t read;
- ssize_t count1;
- char * pnt;
- struct user dump;
-#if defined (__i386__) || defined (__mc68000__)
-# define FIRST_MAPPED PAGE_SIZE /* we don't have page 0 mapped on x86.. */
-#else
-# define FIRST_MAPPED 0
-#endif
-
- memset(&dump, 0, sizeof(struct user));
- dump.magic = CMAGIC;
- dump.u_dsize = max_mapnr;
-#if defined (__i386__)
- dump.start_code = PAGE_OFFSET;
-#endif
-#ifdef __alpha__
- dump.start_data = PAGE_OFFSET;
-#endif
-
- memsize = (max_mapnr + 1) << PAGE_SHIFT;
- if (p >= memsize)
- return 0;
- if (count > memsize - p)
- count = memsize - p;
- read = 0;
-
- if (p < sizeof(struct user) && count > 0) {
- count1 = count;
- if (p + count1 > sizeof(struct user))
- count1 = sizeof(struct user)-p;
- pnt = (char *) &dump + p;
- copy_to_user(buf,(void *) pnt, count1);
- buf += count1;
- p += count1;
- count -= count1;
- read += count1;
- }
-
- if (count > 0 && p < PAGE_SIZE + FIRST_MAPPED) {
- count1 = PAGE_SIZE + FIRST_MAPPED - p;
- if (count1 > count)
- count1 = count;
- clear_user(buf, count1);
- buf += count1;
- p += count1;
- count -= count1;
- read += count1;
- }
- if (count > 0) {
- copy_to_user(buf, (void *) (PAGE_OFFSET+p-PAGE_SIZE), count);
- read += count;
- }
- *ppos += read;
- return read;
-}
-
-static struct file_operations proc_kcore_operations = {
- NULL, /* lseek */
- read_core,
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- open_kcore
-};
-
-struct inode_operations proc_kcore_inode_operations = {
- &proc_kcore_operations,
-};
-
-/*
- * This function accesses profiling information. The returned data is
- * binary: the sampling step and the actual contents of the profile
- * buffer. Use of the program readprofile is recommended in order to
- * get meaningful info out of these data.
- */
-static ssize_t read_profile(struct file *file, char *buf,
- size_t count, loff_t *ppos)
-{
- unsigned long p = *ppos;
- ssize_t read;
- char * pnt;
- unsigned int sample_step = 1 << prof_shift;
-
- if (p >= (prof_len+1)*sizeof(unsigned int))
- return 0;
- if (count > (prof_len+1)*sizeof(unsigned int) - p)
- count = (prof_len+1)*sizeof(unsigned int) - p;
- read = 0;
-
- while (p < sizeof(unsigned int) && count > 0) {
- put_user(*((char *)(&sample_step)+p),buf);
- buf++; p++; count--; read++;
- }
- pnt = (char *)prof_buffer + p - sizeof(unsigned int);
- copy_to_user(buf,(void *)pnt,count);
- read += count;
- *ppos += read;
- return read;
-}
-
-/*
- * Writing to /proc/profile resets the counters
- *
- * Writing a 'profiling multiplier' value into it also re-sets the profiling
- * interrupt frequency, on architectures that support this.
- */
-static ssize_t write_profile(struct file * file, const char * buf,
- size_t count, loff_t *ppos)
-{
-#ifdef __SMP__
- extern int setup_profiling_timer (unsigned int multiplier);
-
- if (count==sizeof(int)) {
- unsigned int multiplier;
-
- if (copy_from_user(&multiplier, buf, sizeof(int)))
- return -EFAULT;
-
- if (setup_profiling_timer(multiplier))
- return -EINVAL;
- }
-#endif
-
- memset(prof_buffer, 0, prof_len * sizeof(*prof_buffer));
- return count;
-}
-
-static struct file_operations proc_profile_operations = {
- NULL, /* lseek */
- read_profile,
- write_profile,
-};
-
-struct inode_operations proc_profile_inode_operations = {
- &proc_profile_operations,
-};
-
-
-static int get_loadavg(char * buffer)
-{
- int a, b, c;
-
- a = avenrun[0] + (FIXED_1/200);
- b = avenrun[1] + (FIXED_1/200);
- c = avenrun[2] + (FIXED_1/200);
- return sprintf(buffer,"%d.%02d %d.%02d %d.%02d %d/%d %d\n",
- LOAD_INT(a), LOAD_FRAC(a),
- LOAD_INT(b), LOAD_FRAC(b),
- LOAD_INT(c), LOAD_FRAC(c),
- nr_running, nr_threads, last_pid);
-}
-
-static int get_kstat(char * buffer)
-{
- int i, len;
- unsigned sum = 0;
- extern unsigned long total_forks;
- unsigned long jif = HZ_TO_STD(jiffies);
-
- for (i = 0 ; i < NR_IRQS ; i++)
- sum += kstat_irqs(i);
-
-#ifdef __SMP__
- len = sprintf(buffer,
- "cpu %u %u %u %lu\n",
- kstat.cpu_user,
- kstat.cpu_nice,
- kstat.cpu_system,
- jif*smp_num_cpus - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system),
- for (i = 0 ; i < smp_num_cpus; i++)
- len += sprintf(buffer + len, "cpu%d %u %u %u %lu\n",
- i,
- kstat.per_cpu_user[cpu_logical_map(i)],
- kstat.per_cpu_nice[cpu_logical_map(i)],
- kstat.per_cpu_system[cpu_logical_map(i)],
- jif - ( kstat.per_cpu_user[cpu_logical_map(i)] \
- + kstat.per_cpu_nice[cpu_logical_map(i)] \
- + kstat.per_cpu_system[cpu_logical_map(i)]));
- len += sprintf(buffer + len,
- "disk %u %u %u %u\n"
- "disk_rio %u %u %u %u\n"
- "disk_wio %u %u %u %u\n"
- "disk_rblk %u %u %u %u\n"
- "disk_wblk %u %u %u %u\n"
- "page %u %u\n"
- "swap %u %u\n"
- "intr %u",
-#else
- len = sprintf(buffer,
- "cpu %u %u %u %lu\n"
- "disk %u %u %u %u\n"
- "disk_rio %u %u %u %u\n"
- "disk_wio %u %u %u %u\n"
- "disk_rblk %u %u %u %u\n"
- "disk_wblk %u %u %u %u\n"
- "page %u %u\n"
- "swap %u %u\n"
- "intr %u",
- HZ_TO_STD(kstat.cpu_user),
- HZ_TO_STD(kstat.cpu_nice),
- HZ_TO_STD(kstat.cpu_system),
- jif*smp_num_cpus - HZ_TO_STD(kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system),
-#endif
- kstat.dk_drive[0], kstat.dk_drive[1],
- kstat.dk_drive[2], kstat.dk_drive[3],
- kstat.dk_drive_rio[0], kstat.dk_drive_rio[1],
- kstat.dk_drive_rio[2], kstat.dk_drive_rio[3],
- kstat.dk_drive_wio[0], kstat.dk_drive_wio[1],
- kstat.dk_drive_wio[2], kstat.dk_drive_wio[3],
- kstat.dk_drive_rblk[0], kstat.dk_drive_rblk[1],
- kstat.dk_drive_rblk[2], kstat.dk_drive_rblk[3],
- kstat.dk_drive_wblk[0], kstat.dk_drive_wblk[1],
- kstat.dk_drive_wblk[2], kstat.dk_drive_wblk[3],
- kstat.pgpgin,
- kstat.pgpgout,
- kstat.pswpin,
- kstat.pswpout,
- sum);
- for (i = 0 ; i < NR_IRQS ; i++)
- len += sprintf(buffer + len, " %u", kstat_irqs(i));
- len += sprintf(buffer + len,
- "\nctxt %u\n"
- "btime %lu\n"
- "processes %lu\n",
- kstat.context_swtch,
- xtime.tv_sec - jif / HZ,
- total_forks);
- return len;
-}
-
-
-static int get_uptime(char * buffer)
-{
- unsigned long uptime;
- unsigned long idle;
-
- uptime = jiffies;
- idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
-
- /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
- that would overflow about every five days at HZ == 100.
- Therefore the identity a = (a / b) * b + a % b is used so that it is
- calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100.
- The part in front of the '+' always evaluates as 0 (mod 100). All divisions
- in the above formulas are truncating. For HZ being a power of 10, the
- calculations simplify to the version in the #else part (if the printf
- format is adapted to the same number of digits as zeroes in HZ.
- */
-#if HZ!=100
- return sprintf(buffer,"%lu.%02lu %lu.%02lu\n",
- uptime / HZ,
- (((uptime % HZ) * 100) / HZ) % 100,
- idle / HZ,
- (((idle % HZ) * 100) / HZ) % 100);
-#else
- return sprintf(buffer,"%lu.%02lu %lu.%02lu\n",
- uptime / HZ,
- uptime % HZ,
- idle / HZ,
- idle % HZ);
-#endif
-}
-
-static int get_meminfo(char * buffer)
-{
- struct sysinfo i;
- int len;
-
-/*
- * display in kilobytes.
- */
-#define K(x) ((x) << (PAGE_SHIFT - 10))
-
- si_meminfo(&i);
- si_swapinfo(&i);
- len = sprintf(buffer, " total: used: free: shared: buffers: cached:\n"
- "Mem: %8lu %8lu %8lu %8lu %8lu %8u\n"
- "Swap: %8lu %8lu %8lu\n",
- K(i.totalram), K(i.totalram-i.freeram), K(i.freeram),
- K(i.sharedram), K(i.bufferram),
- K(atomic_read(&page_cache_size)), K(i.totalswap),
- K(i.totalswap-i.freeswap), K(i.freeswap));
- /*
- * Tagged format, for easy grepping and expansion.
- * The above will go away eventually, once the tools
- * have been updated.
- */
- return len + sprintf(buffer+len,
- "MemTotal: %8lu kB\n"
- "MemFree: %8lu kB\n"
- "MemShared: %8lu kB\n"
- "Buffers: %8lu kB\n"
- "Cached: %8u kB\n"
- "HighTotal: %8lu kB\n"
- "HighFree: %8lu kB\n"
- "SwapTotal: %8lu kB\n"
- "SwapFree: %8lu kB\n",
- K(i.totalram),
- K(i.freeram),
- K(i.sharedram),
- K(i.bufferram),
- K(atomic_read(&page_cache_size)),
- K(i.totalhigh),
- K(i.freehigh),
- K(i.totalswap),
- K(i.freeswap));
-#undef K
-}
-
-static int get_version(char * buffer)
-{
- extern char *linux_banner;
-
- strcpy(buffer, linux_banner);
- return strlen(buffer);
-}
-
-static int get_cmdline(char * buffer)
-{
- extern char saved_command_line[];
-
- return sprintf(buffer, "%s\n", saved_command_line);
-}
-
-static struct page * get_phys_addr(struct mm_struct * mm, unsigned long ptr)
-{
- pgd_t *pgd;
- pmd_t *pmd;
- pte_t pte;
-
- if (ptr >= TASK_SIZE)
- return 0;
- pgd = pgd_offset(mm,ptr);
- if (pgd_none(*pgd))
- return 0;
- if (pgd_bad(*pgd)) {
- pgd_ERROR(*pgd);
- pgd_clear(pgd);
- return 0;
- }
- pmd = pmd_offset(pgd,ptr);
- if (pmd_none(*pmd))
- return 0;
- if (pmd_bad(*pmd)) {
- pmd_ERROR(*pmd);
- pmd_clear(pmd);
- return 0;
- }
- pte = *pte_offset(pmd,ptr);
- if (!pte_present(pte))
- return 0;
- return pte_page(pte);
-}
-
-static int get_array(struct mm_struct *mm, unsigned long start, unsigned long end, char * buffer)
-{
- struct page *page;
- unsigned long kaddr;
- int size = 0, result = 0;
- char c;
-
- if (start >= end)
- return result;
- for (;;) {
- page = get_phys_addr(mm, start);
- if (!page)
- return result;
- kaddr = kmap(page, KM_READ) + (start & ~PAGE_MASK);
- do {
- c = *(char *) kaddr;
- if (!c)
- result = size;
- if (size < PAGE_SIZE)
- buffer[size++] = c;
- else {
- kunmap(kaddr, KM_READ);
- return result;
- }
- kaddr++;
- start++;
- if (!c && start >= end) {
- kunmap(kaddr, KM_READ);
- return result;
- }
- } while (kaddr & ~PAGE_MASK);
- kunmap(kaddr, KM_READ);
- }
- return result;
-}
-
-static struct mm_struct *get_mm(int pid)
-{
- struct task_struct *p;
- struct mm_struct *mm = NULL;
-
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- if (p)
- mm = p->mm;
- if (mm)
- atomic_inc(&mm->mm_users);
- read_unlock(&tasklist_lock);
- return mm;
-}
-
-
-static int get_env(int pid, char * buffer)
-{
- struct mm_struct *mm = get_mm(pid);
- int res = 0;
- if (mm) {
- res = get_array(mm, mm->env_start, mm->env_end, buffer);
- mmput(mm);
- }
- return res;
-}
-
-static int get_arg(int pid, char * buffer)
-{
- struct mm_struct *mm = get_mm(pid);
- int res = 0;
- if (mm) {
- res = get_array(mm, mm->arg_start, mm->arg_end, buffer);
- mmput(mm);
- }
- return res;
-}
-
-/*
- * 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->thread.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 > 8184+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->thread);
- if (pc >= first_sched && pc < last_sched) {
- schedule_frame = ((unsigned long *)p->thread.ksp)[6];
- return ((unsigned long *)schedule_frame)[12];
- }
- return pc;
- }
-#elif defined(__mips__)
- /*
- * The same comment as on the Alpha applies here, too ...
- */
- {
- unsigned long schedule_frame;
- unsigned long pc;
-
- pc = thread_saved_pc(&p->thread);
- if (pc == (unsigned long) interruptible_sleep_on
- || pc == (unsigned long) sleep_on) {
- schedule_frame = ((unsigned long *)p->thread.reg30)[9];
- return ((unsigned long *)schedule_frame)[15];
- }
- if (pc == (unsigned long) interruptible_sleep_on_timeout
- || pc == (unsigned long) sleep_on_timeout) {
- schedule_frame = ((unsigned long *)p->thread.reg30)[9];
- return ((unsigned long *)schedule_frame)[16];
- }
- if (pc >= first_sched && pc < last_sched) {
- printk(KERN_DEBUG "Bug in %s\n", __FUNCTION__);
- }
-
- 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->thread.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__)
- {
- unsigned long ip, sp;
- unsigned long stack_page = (unsigned long) p;
- int count = 0;
-
- sp = p->thread.ksp;
- do {
- sp = *(unsigned long *)sp;
- if (sp < stack_page || sp >= stack_page + 8188)
- return 0;
- if (count > 0) {
- ip = *(unsigned long *)(sp + 4);
- if (ip < first_sched || ip >= last_sched)
- return ip;
- }
- } while (count++ < 16);
- }
-#elif defined(__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->thread.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)->thread.usp)
-#elif defined(__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)->thread.esp0 > PAGE_SIZE && \
- MAP_NR((tsk)->thread.esp0) < max_mapnr) \
- eip = ((struct pt_regs *) (tsk)->thread.esp0)->pc; \
- eip; })
-#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
-#elif defined(__powerpc__)
-#define KSTK_EIP(tsk) ((tsk)->thread.regs->nip)
-#define KSTK_ESP(tsk) ((tsk)->thread.regs->gpr[1])
-#elif defined (__sparc_v9__)
-# define KSTK_EIP(tsk) ((tsk)->thread.kregs->tpc)
-# define KSTK_ESP(tsk) ((tsk)->thread.kregs->u_regs[UREG_FP])
-#elif defined(__sparc__)
-# define KSTK_EIP(tsk) ((tsk)->thread.kregs->pc)
-# define KSTK_ESP(tsk) ((tsk)->thread.kregs->u_regs[UREG_FP])
-#elif defined(__mips__)
-# define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg \
- - sizeof(struct pt_regs))
-#define KSTK_TOS(tsk) ((unsigned long)(tsk) + KERNEL_STACK_SIZE - 32)
-# define KSTK_EIP(tsk) (*(unsigned long *)(KSTK_TOS(tsk) + PT_REG(cp0_epc)))
-# define KSTK_ESP(tsk) (*(unsigned long *)(KSTK_TOS(tsk) + PT_REG(regs[29])))
-#elif defined(__sh__)
-# define KSTK_EIP(tsk) ((tsk)->thread.pc)
-# define KSTK_ESP(tsk) ((tsk)->thread.sp)
-#endif
+#include <asm/processor.h>
/* Gcc optimizes away "strlen(x)" for constant x */
#define ADDBUF(buffer, string) \
@@ -913,36 +264,27 @@ extern inline char *task_cap(struct task_struct *p, char *buffer)
}
-static int get_status(int pid, char * buffer)
+/* task is locked, so we are safe here */
+
+int proc_pid_status(struct task_struct *task, char * buffer)
{
char * orig = buffer;
- struct task_struct *tsk;
- struct mm_struct *mm = NULL;
+ struct mm_struct *mm = task->mm;
- read_lock(&tasklist_lock);
- tsk = find_task_by_pid(pid);
- if (tsk)
- mm = tsk->mm;
- if (mm)
- atomic_inc(&mm->mm_users);
- read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
- if (!tsk)
- return 0;
- buffer = task_name(tsk, buffer);
- buffer = task_state(tsk, buffer);
+ buffer = task_name(task, buffer);
+ buffer = task_state(task, buffer);
if (mm)
buffer = task_mem(mm, buffer);
- buffer = task_sig(tsk, buffer);
- buffer = task_cap(tsk, buffer);
- if (mm)
- mmput(mm);
+ buffer = task_sig(task, buffer);
+ buffer = task_cap(task, buffer);
return buffer - orig;
}
-static int get_stat(int pid, char * buffer)
+/* task is locked, so we are safe here */
+
+int proc_pid_stat(struct task_struct *task, char * buffer)
{
- struct task_struct *tsk;
- struct mm_struct *mm = NULL;
+ struct mm_struct *mm = task->mm;
unsigned long vsize, eip, esp, wchan;
long priority, nice;
int tty_pgrp;
@@ -950,16 +292,7 @@ static int get_stat(int pid, char * buffer)
char state;
int res;
- read_lock(&tasklist_lock);
- tsk = find_task_by_pid(pid);
- if (tsk)
- mm = tsk->mm;
- if (mm)
- atomic_inc(&mm->mm_users);
- read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
- if (!tsk)
- return 0;
- state = *get_task_state(tsk);
+ state = *get_task_state(task);
vsize = eip = esp = 0;
if (mm) {
struct vm_area_struct *vma;
@@ -969,55 +302,55 @@ static int get_stat(int pid, char * buffer)
vsize += vma->vm_end - vma->vm_start;
vma = vma->vm_next;
}
- eip = KSTK_EIP(tsk);
- esp = KSTK_ESP(tsk);
+ eip = KSTK_EIP(task);
+ esp = KSTK_ESP(task);
up(&mm->mmap_sem);
}
- wchan = get_wchan(tsk);
+ wchan = get_wchan(task);
- collect_sigign_sigcatch(tsk, &sigign, &sigcatch);
+ collect_sigign_sigcatch(task, &sigign, &sigcatch);
- if (tsk->tty)
- tty_pgrp = tsk->tty->pgrp;
+ if (task->tty)
+ tty_pgrp = task->tty->pgrp;
else
tty_pgrp = -1;
/* scale priority and nice values from timeslices to -20..20 */
/* to make it look like a "normal" Unix priority/nice value */
- priority = tsk->counter;
+ priority = task->counter;
priority = 20 - (priority * 10 + DEF_PRIORITY / 2) / DEF_PRIORITY;
- nice = tsk->priority;
+ nice = task->priority;
nice = 20 - (nice * 20 + DEF_PRIORITY / 2) / DEF_PRIORITY;
res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
- pid,
- tsk->comm,
+ task->pid,
+ task->comm,
state,
- tsk->p_pptr->pid,
- tsk->pgrp,
- tsk->session,
- tsk->tty ? kdev_t_to_nr(tsk->tty->device) : 0,
+ task->p_pptr->pid,
+ task->pgrp,
+ task->session,
+ task->tty ? kdev_t_to_nr(task->tty->device) : 0,
tty_pgrp,
- tsk->flags,
- tsk->min_flt,
- tsk->cmin_flt,
- tsk->maj_flt,
- tsk->cmaj_flt,
- HZ_TO_STD(tsk->times.tms_utime),
- HZ_TO_STD(tsk->times.tms_stime),
- HZ_TO_STD(tsk->times.tms_cutime),
- HZ_TO_STD(tsk->times.tms_cstime),
+ task->flags,
+ task->min_flt,
+ task->cmin_flt,
+ task->maj_flt,
+ task->cmaj_flt,
+ task->times.tms_utime,
+ task->times.tms_stime,
+ task->times.tms_cutime,
+ task->times.tms_cstime,
priority,
nice,
0UL /* removed */,
- tsk->it_real_value,
- tsk->start_time,
+ task->it_real_value,
+ task->start_time,
vsize,
mm ? mm->rss : 0, /* you might want to shift this left 3 */
- tsk->rlim ? tsk->rlim[RLIMIT_RSS].rlim_cur : 0,
+ task->rlim ? task->rlim[RLIMIT_RSS].rlim_cur : 0,
mm ? mm->start_code : 0,
mm ? mm->end_code : 0,
mm ? mm->start_stack : 0,
@@ -1027,17 +360,15 @@ static int get_stat(int pid, char * buffer)
* It must be decimal for Linux 2.0 compatibility.
* Use /proc/#/status for real-time signals.
*/
- tsk->signal .sig[0] & 0x7fffffffUL,
- tsk->blocked.sig[0] & 0x7fffffffUL,
+ task->signal .sig[0] & 0x7fffffffUL,
+ task->blocked.sig[0] & 0x7fffffffUL,
sigign .sig[0] & 0x7fffffffUL,
sigcatch .sig[0] & 0x7fffffffUL,
wchan,
- tsk->nswap,
- tsk->cnswap,
- tsk->exit_signal,
- tsk->processor);
- if (mm)
- mmput(mm);
+ task->nswap,
+ task->cnswap,
+ task->exit_signal,
+ task->processor);
return res;
}
@@ -1072,9 +403,9 @@ static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned
++*pages;
if (pte_dirty(page))
++*dirty;
- if (MAP_NR(pte_page(page)) >= max_mapnr)
+ if (pte_pagenr(page) >= max_mapnr)
continue;
- if (page_count(mem_map + MAP_NR(pte_page(page))) > 1)
+ if (page_count(pte_page(page)) > 1)
++*shared;
} while (address < end);
}
@@ -1114,9 +445,9 @@ static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long en
}
}
-static int get_statm(int pid, char * buffer)
+int proc_pid_statm(struct task_struct *task, char * buffer)
{
- struct mm_struct *mm = get_mm(pid);
+ struct mm_struct *mm = task->mm;
int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
if (mm) {
@@ -1143,7 +474,6 @@ static int get_statm(int pid, char * buffer)
vma = vma->vm_next;
}
up(&mm->mmap_sem);
- mmput(mm);
}
return sprintf(buffer,"%d %d %d %d %d %d %d\n",
size, resident, share, trs, lrs, drs, dt);
@@ -1182,10 +512,10 @@ static int get_statm(int pid, char * buffer)
#define MAPS_LINE_MAX MAPS_LINE_MAX8
-static ssize_t read_maps (int pid, struct file * file, char * buf,
+ssize_t proc_pid_read_maps (struct task_struct *task, struct file * file, char * buf,
size_t count, loff_t *ppos)
{
- struct task_struct *p;
+ struct mm_struct *mm = task->mm;
struct vm_area_struct * map, * next;
char * destptr = buf, * buffer;
loff_t lineno;
@@ -1201,25 +531,19 @@ static ssize_t read_maps (int pid, struct file * file, char * buf,
if (!buffer)
goto out;
- retval = -EINVAL;
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
- if (!p)
- goto freepage_out;
-
- if (!p->mm || count == 0)
+ if (!mm || count == 0)
goto getlen_out;
/* Check whether the mmaps could change if we sleep */
- volatile_task = (p != current || atomic_read(&p->mm->mm_users) > 1);
+ volatile_task = (task != current || atomic_read(&mm->mm_users) > 1);
/* decode f_pos */
lineno = *ppos >> MAPS_LINE_SHIFT;
column = *ppos & (MAPS_LINE_LENGTH-1);
/* quickly go to line lineno */
- for (map = p->mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
+ down(&mm->mmap_sem);
+ for (map = mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
continue;
for ( ; map ; map = next ) {
@@ -1260,7 +584,7 @@ static ssize_t read_maps (int pid, struct file * file, char * buf,
len = sprintf(line,
sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8,
- map->vm_start, map->vm_end, str, map->vm_offset,
+ map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
kdevname(dev), ino);
if(map->vm_file) {
@@ -1278,7 +602,9 @@ static ssize_t read_maps (int pid, struct file * file, char * buf,
i = len-column;
if (i > count)
i = count;
+ up(&mm->mmap_sem);
copy_to_user(destptr, line+column, i); /* may have slept */
+ down(&mm->mmap_sem);
destptr += i;
count -= i;
column += i;
@@ -1297,382 +623,34 @@ static ssize_t read_maps (int pid, struct file * file, char * buf,
if (volatile_task)
break;
}
+ up(&mm->mmap_sem);
/* encode f_pos */
*ppos = (lineno << MAPS_LINE_SHIFT) + column;
getlen_out:
retval = destptr - buf;
-
-freepage_out:
free_page((unsigned long)buffer);
out:
return retval;
}
#ifdef __SMP__
-static int get_pidcpu(int pid, char * buffer)
+int proc_pid_cpu(struct task_struct *task, char * buffer)
{
- struct task_struct * tsk = current ;
- int i, len = 0;
-
- read_lock(&tasklist_lock);
- if (pid != tsk->pid)
- tsk = find_task_by_pid(pid);
- read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
-
- if (tsk == NULL)
- return 0;
+ int i, len;
len = sprintf(buffer,
"cpu %lu %lu\n",
- HZ_TO_STD(tsk->times.tms_utime),
- HZ_TO_STD(tsk->times.tms_stime));
-
+ task->times.tms_utime,
+ task->times.tms_stime);
+
for (i = 0 ; i < smp_num_cpus; i++)
len += sprintf(buffer + len, "cpu%d %lu %lu\n",
i,
- HZ_TO_STD(tsk->per_cpu_utime[cpu_logical_map(i)]),
- HZ_TO_STD(tsk->per_cpu_stime[cpu_logical_map(i)]));
+ task->per_cpu_utime[cpu_logical_map(i)],
+ task->per_cpu_stime[cpu_logical_map(i)]);
return len;
}
#endif
-
-#ifdef CONFIG_MODULES
-extern int get_module_list(char *);
-extern int get_ksyms_list(char *, char **, off_t, int);
-#endif
-extern int get_device_list(char *);
-extern int get_partition_list(char *);
-extern int get_filesystem_list(char *);
-extern int get_filesystem_info( char * );
-extern int get_irq_list(char *);
-extern int get_dma_list(char *);
-extern int get_cpuinfo(char *);
-extern int get_pci_list(char *);
-extern int get_md_status (char *);
-extern int get_rtc_status (char *);
-extern int get_locks_status (char *, char **, off_t, int);
-extern int get_swaparea_info (char *);
-extern int get_hardware_list(char *);
-extern int get_stram_list(char *);
-
-static long get_root_array(char * page, int type, char **start,
- off_t offset, unsigned long length)
-{
- switch (type) {
- case PROC_LOADAVG:
- return get_loadavg(page);
-
- case PROC_UPTIME:
- return get_uptime(page);
-
- case PROC_MEMINFO:
- return get_meminfo(page);
-
-#ifdef CONFIG_PCI
- case PROC_PCI:
- return get_pci_list(page);
-#endif
-
-#ifdef CONFIG_NUBUS
- case PROC_NUBUS:
- return get_nubus_list(page);
-#endif
-
- case PROC_CPUINFO:
- return get_cpuinfo(page);
-
- case PROC_VERSION:
- return get_version(page);
-
-#ifdef CONFIG_DEBUG_MALLOC
- case PROC_MALLOC:
- return get_malloc(page);
-#endif
-
-#ifdef CONFIG_MODULES
- case PROC_MODULES:
- return get_module_list(page);
-
- case PROC_KSYMS:
- return get_ksyms_list(page, start, offset, length);
-#endif
-
- case PROC_STAT:
- return get_kstat(page);
-
- case PROC_SLABINFO:
- return get_slabinfo(page);
-
- case PROC_DEVICES:
- return get_device_list(page);
-
- case PROC_PARTITIONS:
- return get_partition_list(page);
-
- case PROC_INTERRUPTS:
- return get_irq_list(page);
-
- case PROC_FILESYSTEMS:
- return get_filesystem_list(page);
-
- case PROC_DMA:
- return get_dma_list(page);
-
- case PROC_IOPORTS:
- return get_ioport_list(page);
-
- case PROC_MEMORY:
- return get_mem_list(page);
-#ifdef CONFIG_BLK_DEV_MD
- case PROC_MD:
- return get_md_status(page);
-#endif
- case PROC_CMDLINE:
- return get_cmdline(page);
-
- case PROC_MTAB:
- return get_filesystem_info( page );
-
- case PROC_SWAP:
- return get_swaparea_info(page);
-#ifdef CONFIG_RTC
- case PROC_RTC:
- return get_rtc_status(page);
-#endif
-#ifdef CONFIG_SGI_DS1286
- case PROC_RTC:
- return get_ds1286_status(page);
-#endif
- case PROC_LOCKS:
- return get_locks_status(page, start, offset, length);
-#ifdef CONFIG_PROC_HARDWARE
- case PROC_HARDWARE:
- return get_hardware_list(page);
-#endif
-#ifdef CONFIG_STRAM_PROC
- case PROC_STRAM:
- return get_stram_list(page);
-#endif
- }
- return -EBADF;
-}
-
-static int process_unauthorized(int type, int pid)
-{
- struct task_struct *p;
- uid_t euid=0; /* Save the euid keep the lock short */
- int ok = 0;
-
- read_lock(&tasklist_lock);
-
- /*
- * Grab the lock, find the task, save the uid and
- * check it has an mm still (ie its not dead)
- */
-
- p = find_task_by_pid(pid);
- if (p) {
- euid=p->euid;
- ok = p->dumpable;
- if(!cap_issubset(p->cap_permitted, current->cap_permitted))
- ok=0;
- }
-
- read_unlock(&tasklist_lock);
-
- if (!p)
- return 1;
-
- switch(type) {
- case PROC_PID_STATUS:
- case PROC_PID_STATM:
- case PROC_PID_STAT:
- case PROC_PID_MAPS:
- case PROC_PID_CMDLINE:
- case PROC_PID_CPU:
- return 0;
- }
- if(capable(CAP_DAC_OVERRIDE) || (current->fsuid == euid && ok))
- return 0;
- return 1;
-}
-
-
-static int get_process_array(char * page, int pid, int type)
-{
- switch (type) {
- case PROC_PID_STATUS:
- return get_status(pid, page);
- case PROC_PID_ENVIRON:
- return get_env(pid, page);
- case PROC_PID_CMDLINE:
- return get_arg(pid, page);
- case PROC_PID_STAT:
- return get_stat(pid, page);
- case PROC_PID_STATM:
- return get_statm(pid, page);
-#ifdef __SMP__
- case PROC_PID_CPU:
- return get_pidcpu(pid, page);
-#endif
- }
- return -EBADF;
-}
-
-
-static inline int fill_array(char * page, int pid, int type, char **start, off_t offset, int length)
-{
- if (pid)
- return get_process_array(page, pid, type);
- return get_root_array(page, type, start, offset, length);
-}
-
-#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
-
-static ssize_t array_read(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- struct inode * inode = file->f_dentry->d_inode;
- unsigned long page;
- char *start;
- ssize_t length;
- ssize_t end;
- unsigned int type, pid;
- struct proc_dir_entry *dp;
-
- if (count > PROC_BLOCK_SIZE)
- count = PROC_BLOCK_SIZE;
- if (!(page = __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- type = inode->i_ino;
- pid = type >> 16;
- type &= 0x0000ffff;
- start = NULL;
- dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
- if (pid && process_unauthorized(type, pid)) {
- free_page(page);
- return -EIO;
- }
-
- if (dp->get_info)
- length = dp->get_info((char *)page, &start, *ppos,
- count, 0);
- else
- length = fill_array((char *) page, pid, type,
- &start, *ppos, count);
- if (length < 0) {
- free_page(page);
- return length;
- }
- if (start != NULL) {
- /* We have had block-adjusting processing! */
- copy_to_user(buf, start, length);
- *ppos += length;
- count = length;
- } else {
- /* Static 4kB (or whatever) block capacity */
- if (*ppos >= length) {
- free_page(page);
- return 0;
- }
- if (count + *ppos > length)
- count = length - *ppos;
- end = count + *ppos;
- copy_to_user(buf, (char *) page + *ppos, count);
- *ppos = end;
- }
- free_page(page);
- return count;
-}
-
-static struct file_operations proc_array_operations = {
- NULL, /* array_lseek */
- array_read,
- NULL, /* array_write */
- NULL, /* array_readdir */
- NULL, /* array_poll */
- NULL, /* array_ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-struct inode_operations proc_array_inode_operations = {
- &proc_array_operations, /* default base directory file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-static ssize_t arraylong_read(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- struct inode * inode = file->f_dentry->d_inode;
- unsigned int pid = inode->i_ino >> 16;
- unsigned int type = inode->i_ino & 0x0000ffff;
-
- switch (type) {
- case PROC_PID_MAPS:
- return read_maps(pid, file, buf, count, ppos);
- }
- return -EINVAL;
-}
-
-static struct file_operations proc_arraylong_operations = {
- NULL, /* array_lseek */
- arraylong_read,
- NULL, /* array_write */
- NULL, /* array_readdir */
- NULL, /* array_poll */
- NULL, /* array_ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-struct inode_operations proc_arraylong_inode_operations = {
- &proc_arraylong_operations, /* default base directory file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
diff --git a/fs/proc/base.c b/fs/proc/base.c
index f0a0febf8..866bb50d4 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -4,6 +4,13 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*
* proc base directory handling functions
+ *
+ * 1999, Al Viro. Rewritten. Now it covers the whole per-process part.
+ * Instead of using magical inumbers to determine the kind of object
+ * we allocate and fill in-core inodes upon lookup. They don't even
+ * go into icache. We cache the reference to task_struct upon lookup too.
+ * Eventually it should become a filesystem in its own. We don't use the
+ * rest of procfs anymore.
*/
#include <asm/uaccess.h>
@@ -14,28 +21,336 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/init.h>
-
-static struct file_operations proc_base_operations = {
- NULL, /* lseek - default */
- NULL, /* read - bad */
- NULL, /* write - bad */
- proc_readdir, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
+#include <linux/file.h>
/*
- * proc directories can do almost nothing..
+ * For hysterical raisins we keep the same inumbers as in the old procfs.
+ * Feel free to change the macro below - just keep the range distinct from
+ * inumbers of the rest of procfs (currently those are in 0x0000--0xffff).
+ * As soon as we'll get a separate superblock we will be able to forget
+ * about magical ranges too.
*/
-static struct inode_operations proc_base_inode_operations = {
- &proc_base_operations, /* default base directory file-ops */
+
+#define fake_ino(pid,ino) (((pid)<<16)|(ino))
+
+ssize_t proc_pid_read_maps(struct task_struct*,struct file*,char*,size_t,loff_t*);
+int proc_pid_stat(struct task_struct*,char*);
+int proc_pid_status(struct task_struct*,char*);
+int proc_pid_statm(struct task_struct*,char*);
+int proc_pid_cpu(struct task_struct*,char*);
+
+static struct dentry *proc_fd_link(struct inode *inode)
+{
+ if (inode->u.proc_i.file)
+ return dget(inode->u.proc_i.file->f_dentry);
+ return NULL;
+}
+
+static struct dentry *proc_exe_link(struct inode *inode)
+{
+ struct mm_struct * mm;
+ struct vm_area_struct * vma;
+ struct dentry *result = NULL;
+ struct task_struct *task = inode->u.proc_i.task;
+
+ if (!task_lock(task))
+ return NULL;
+ mm = task->mm;
+ if (!mm)
+ goto out;
+ down(&mm->mmap_sem);
+ vma = mm->mmap;
+ while (vma) {
+ if ((vma->vm_flags & VM_EXECUTABLE) &&
+ vma->vm_file) {
+ result = dget(vma->vm_file->f_dentry);
+ break;
+ }
+ vma = vma->vm_next;
+ }
+ up(&mm->mmap_sem);
+out:
+ task_unlock(task);
+ return result;
+}
+
+static struct dentry *proc_cwd_link(struct inode *inode)
+{
+ struct dentry *result = NULL;
+ if (task_lock(inode->u.proc_i.task)) {
+ struct fs_struct *fs = inode->u.proc_i.task->fs;
+ if (fs)
+ result = dget(fs->pwd);
+ task_unlock(inode->u.proc_i.task);
+ }
+ return result;
+}
+
+static struct dentry *proc_root_link(struct inode *inode)
+{
+ struct dentry *result = NULL;
+ if (task_lock(inode->u.proc_i.task)) {
+ struct fs_struct *fs = inode->u.proc_i.task->fs;
+ if (fs)
+ result = dget(fs->root);
+ task_unlock(inode->u.proc_i.task);
+ }
+ return result;
+}
+
+/* task is locked and can't drop mm, so we are safe */
+
+static int proc_pid_environ(struct task_struct *task, char * buffer)
+{
+ struct mm_struct *mm = task->mm;
+ int res = 0;
+ if (mm)
+ res = access_process_vm(task, mm->env_start, buffer,
+ mm->env_end - mm->env_start, 0);
+ return res;
+}
+
+/* task is locked and can't drop mm, so we are safe */
+
+static int proc_pid_cmdline(struct task_struct *task, char * buffer)
+{
+ struct mm_struct *mm = task->mm;
+ int res = 0;
+ if (mm)
+ res = access_process_vm(task, mm->arg_start, buffer,
+ mm->arg_end - mm->arg_start, 0);
+ return res;
+}
+
+/************************************************************************/
+/* Here the fs part begins */
+/************************************************************************/
+
+/* permission checks */
+
+static int standard_permission(struct inode *inode, int mask)
+{
+ int mode = inode->i_mode;
+
+ if ((mask & S_IWOTH) && IS_RDONLY(inode) &&
+ (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
+ return -EROFS; /* Nobody gets write access to a read-only fs */
+ else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
+ return -EACCES; /* Nobody gets write access to an immutable file */
+ else if (current->fsuid == inode->i_uid)
+ mode >>= 6;
+ else if (in_group_p(inode->i_gid))
+ mode >>= 3;
+ if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE))
+ return 0;
+ /* read and search access */
+ if ((mask == S_IROTH) ||
+ (S_ISDIR(mode) && !(mask & ~(S_IROTH | S_IXOTH))))
+ if (capable(CAP_DAC_READ_SEARCH))
+ return 0;
+ return -EACCES;
+}
+
+static int proc_permission(struct inode *inode, int mask)
+{
+ struct dentry *de, *base, *root;
+ struct super_block *our_sb, *sb, *below;
+
+ if (standard_permission(inode, mask) != 0)
+ return -EACCES;
+
+ base = current->fs->root;
+ de = root = proc_root_link(inode); /* Ewww... */
+
+ if (!de)
+ return -ENOENT;
+
+ our_sb = base->d_inode->i_sb;
+ sb = de->d_inode->i_sb;
+ while (sb != our_sb) {
+ de = sb->s_root->d_covers;
+ below = de->d_inode->i_sb;
+ if (sb == below)
+ goto out;
+ sb = below;
+ }
+
+ if (!is_subdir(de, base))
+ goto out;
+
+ dput(root);
+ return 0;
+out:
+ dput(root);
+ return -EACCES;
+}
+
+static ssize_t pid_maps_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
+{
+ struct inode * inode = file->f_dentry->d_inode;
+ struct task_struct *task = inode->u.proc_i.task;
+ ssize_t res;
+
+ if (!task_lock(task))
+ return -EIO;
+ res = proc_pid_read_maps(task, file, buf, count, ppos);
+ task_unlock(task);
+ return res;
+}
+
+static struct file_operations proc_maps_operations = {
+ NULL, /* array_lseek */
+ pid_maps_read,
+};
+
+struct inode_operations proc_maps_inode_operations = {
+ &proc_maps_operations, /* default base directory file-ops */
+};
+
+#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
+
+static ssize_t proc_info_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
+{
+ struct inode * inode = file->f_dentry->d_inode;
+ unsigned long page;
+ ssize_t length;
+ ssize_t end;
+ struct task_struct *task = inode->u.proc_i.task;
+
+ if (count > PROC_BLOCK_SIZE)
+ count = PROC_BLOCK_SIZE;
+ if (!(page = __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+
+ if (!task_lock(task)) {
+ free_page(page);
+ return -EIO;
+ }
+
+ length = inode->u.proc_i.op.proc_read(task, (char*)page);
+
+ task_unlock(task);
+
+ if (length < 0) {
+ free_page(page);
+ return length;
+ }
+ /* Static 4kB (or whatever) block capacity */
+ if (*ppos >= length) {
+ free_page(page);
+ return 0;
+ }
+ if (count + *ppos > length)
+ count = length - *ppos;
+ end = count + *ppos;
+ copy_to_user(buf, (char *) page + *ppos, count);
+ *ppos = end;
+ free_page(page);
+ return count;
+}
+
+static struct file_operations proc_info_file_operations = {
+ NULL, /* lseek */
+ proc_info_read, /* read */
+};
+
+static struct inode_operations proc_info_inode_operations = {
+ &proc_info_file_operations, /* default proc file-ops */
+};
+
+#define MAY_PTRACE(p) \
+(p==current||(p->p_pptr==current&&(p->flags&PF_PTRACED)&&p->state==TASK_STOPPED))
+
+static ssize_t mem_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
+{
+ struct task_struct *task = file->f_dentry->d_inode->u.proc_i.task;
+ char *page;
+ unsigned long src = *ppos;
+ int copied = 0;
+
+ if (!MAY_PTRACE(task))
+ return -ESRCH;
+
+ page = (char *)__get_free_page(GFP_USER);
+ if (!page)
+ return -ENOMEM;
+
+ while (count > 0) {
+ int this_len, retval;
+
+ this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+ retval = access_process_vm(task, src, page, this_len, 0);
+ if (!retval) {
+ if (!copied)
+ copied = -EIO;
+ break;
+ }
+ if (copy_to_user(buf, page, retval)) {
+ copied = -EFAULT;
+ break;
+ }
+ copied += retval;
+ src += retval;
+ buf += retval;
+ count -= retval;
+ }
+ *ppos = src;
+ free_page((unsigned long) page);
+ return copied;
+}
+
+static ssize_t mem_write(struct file * file, const char * buf,
+ size_t count, loff_t *ppos)
+{
+ int copied = 0;
+ char *page;
+ struct task_struct *task = file->f_dentry->d_inode->u.proc_i.task;
+ unsigned long dst = *ppos;
+
+ if (!MAY_PTRACE(task))
+ return -ESRCH;
+
+ page = (char *)__get_free_page(GFP_USER);
+ if (!page)
+ return -ENOMEM;
+
+ while (count > 0) {
+ int this_len, retval;
+
+ this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+ if (copy_from_user(page, buf, this_len)) {
+ copied = -EFAULT;
+ break;
+ }
+ retval = access_process_vm(task, dst, page, this_len, 1);
+ if (!retval) {
+ if (!copied)
+ copied = -EIO;
+ break;
+ }
+ copied += retval;
+ buf += retval;
+ dst += retval;
+ count -= retval;
+ }
+ *ppos = dst;
+ free_page((unsigned long) page);
+ return copied;
+}
+
+static struct file_operations proc_mem_operations = {
+ NULL, /* lseek - default */
+ mem_read,
+ mem_write,
+};
+
+static struct inode_operations proc_mem_inode_operations = {
+ &proc_mem_operations, /* default base directory file-ops */
NULL, /* create */
- proc_lookup, /* lookup */
+ NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
@@ -50,161 +365,653 @@ static struct inode_operations proc_base_inode_operations = {
NULL, /* writepage */
NULL, /* flushpage */
NULL, /* truncate */
- NULL, /* permission */
+ proc_permission, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
-/*
- * The fill argument is non-zero when the inode is being filled ...
- * we don't need to do anything when it's being deleted.
- */
-static void proc_pid_fill_inode(struct inode * inode, int fill)
+static struct dentry * proc_pid_follow_link(struct dentry *dentry,
+ struct dentry *base,
+ unsigned int follow)
{
- struct task_struct *p;
- int pid = inode->i_ino >> 16;
- int ino = inode->i_ino & 0xffff;
+ struct inode *inode = dentry->d_inode;
+ struct dentry * result;
+ int error;
- read_lock(&tasklist_lock);
- if (fill && (p = find_task_by_pid(pid)) != NULL) {
- uid_t uid = 0;
- gid_t gid = 0;
- if (p->dumpable || ino == PROC_PID_INO) {
- uid = p->euid;
- gid = p->egid;
- }
- inode->i_uid = uid;
- inode->i_gid = gid;
+ /* We don't need a base pointer in the /proc filesystem */
+ dput(base);
+
+ error = proc_permission(inode, MAY_EXEC);
+ result = ERR_PTR(error);
+ if (error)
+ goto out;
+
+ result = inode->u.proc_i.op.proc_get_link(inode);
+out:
+ if (!result)
+ result = ERR_PTR(-ENOENT);
+ return result;
+}
+
+static int do_proc_readlink(struct dentry *dentry, char * buffer, int buflen)
+{
+ struct inode * inode;
+ char * tmp = (char*)__get_free_page(GFP_KERNEL), *path, *pattern;
+ int len;
+
+ if (!tmp)
+ return -ENOMEM;
+
+ /* Check for special dentries.. */
+ pattern = NULL;
+ inode = dentry->d_inode;
+ if (inode && IS_ROOT(dentry)) {
+ if (S_ISSOCK(inode->i_mode))
+ pattern = "socket:[%lu]";
+ if (S_ISFIFO(inode->i_mode))
+ pattern = "pipe:[%lu]";
}
- read_unlock(&tasklist_lock);
+
+ if (pattern) {
+ len = sprintf(tmp, pattern, inode->i_ino);
+ path = tmp;
+ } else {
+ path = d_path(dentry, tmp, PAGE_SIZE);
+ len = tmp + PAGE_SIZE - 1 - path;
+ }
+
+ if (len < buflen)
+ buflen = len;
+ copy_to_user(buffer, path, buflen);
+ free_page((unsigned long)tmp);
+ return buflen;
}
-/*
- * This is really a pseudo-entry, and only links
- * backwards to the parent with no link from the
- * root directory to this. This way we can have just
- * one entry for every /proc/<pid>/ directory.
- */
-struct proc_dir_entry proc_pid = {
- PROC_PID_INO, 5, "<pid>",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_base_inode_operations,
- NULL, proc_pid_fill_inode,
- NULL, &proc_root, NULL
-};
-
-static struct proc_dir_entry proc_pid_status = {
- PROC_PID_STATUS, 6, "status",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_mem = {
- PROC_PID_MEM, 3, "mem",
- S_IFREG | S_IRUSR | S_IWUSR, 1, 0, 0,
- 0, &proc_mem_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_cwd = {
- PROC_PID_CWD, 3, "cwd",
- S_IFLNK | S_IRWXU, 1, 0, 0,
- 0, &proc_link_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_root = {
- PROC_PID_ROOT, 4, "root",
- S_IFLNK | S_IRWXU, 1, 0, 0,
- 0, &proc_link_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_exe = {
- PROC_PID_EXE, 3, "exe",
- S_IFLNK | S_IRWXU, 1, 0, 0,
- 0, &proc_link_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_fd = {
- PROC_PID_FD, 2, "fd",
- S_IFDIR | S_IRUSR | S_IXUSR, 2, 0, 0,
- 0, &proc_fd_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_environ = {
- PROC_PID_ENVIRON, 7, "environ",
- S_IFREG | S_IRUSR, 1, 0, 0,
- 0, &proc_array_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_cmdline = {
- PROC_PID_CMDLINE, 7, "cmdline",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_stat = {
- PROC_PID_STAT, 4, "stat",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_statm = {
- PROC_PID_STATM, 5, "statm",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_maps = {
- PROC_PID_MAPS, 4, "maps",
- S_IFIFO | S_IRUGO, 1, 0, 0,
- 0, &proc_arraylong_inode_operations,
- NULL, proc_pid_fill_inode,
+static int proc_pid_readlink(struct dentry * dentry, char * buffer, int buflen)
+{
+ int error;
+ struct inode *inode = dentry->d_inode;
+
+ error = proc_permission(inode, MAY_EXEC);
+ if (error)
+ goto out;
+
+ dentry = inode->u.proc_i.op.proc_get_link(inode);
+ error = -ENOENT;
+ if (!dentry)
+ goto out;
+
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ goto out;
+
+ error = do_proc_readlink(dentry, buffer, buflen);
+ dput(dentry);
+out:
+ return error;
+}
+
+static struct inode_operations proc_pid_link_inode_operations = {
+ NULL, /* file-operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ proc_pid_readlink, /* readlink */
+ proc_pid_follow_link, /* follow_link */
};
+/* reading from directory - bad */
+
+static ssize_t proc_dir_read (struct file * filp, char * buf,
+ size_t count, loff_t *ppos)
+{
+ return -EISDIR;
+}
+
+struct pid_entry {
+ int type;
+ int len;
+ char *name;
+ mode_t mode;
+};
+
+enum pid_directory_inos {
+ PROC_PID_INO = 2,
+ PROC_PID_STATUS,
+ PROC_PID_MEM,
+ PROC_PID_CWD,
+ PROC_PID_ROOT,
+ PROC_PID_EXE,
+ PROC_PID_FD,
+ PROC_PID_ENVIRON,
+ PROC_PID_CMDLINE,
+ PROC_PID_STAT,
+ PROC_PID_STATM,
+ PROC_PID_MAPS,
#if CONFIG_AP1000
-static struct proc_dir_entry proc_pid_ringbuf = {
- PROC_PID_RINGBUF, 7, "ringbuf",
- S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
- 0, &proc_ringbuf_inode_operations,
- NULL, proc_pid_fill_inode,
+ PROC_PID_RINGBUF,
+#endif
+ PROC_PID_CPU,
+ PROC_PID_FD_DIR = 0x8000, /* 0x8000-0xffff */
};
+
+#define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
+static struct pid_entry base_stuff[] = {
+ E(PROC_PID_FD, "fd", S_IFDIR|S_IRUSR|S_IXUSR),
+ E(PROC_PID_ENVIRON, "environ", S_IFREG|S_IRUSR),
+ E(PROC_PID_STATUS, "status", S_IFREG|S_IRUGO),
+ E(PROC_PID_CMDLINE, "cmdline", S_IFREG|S_IRUGO),
+ E(PROC_PID_STAT, "stat", S_IFREG|S_IRUGO),
+ E(PROC_PID_STATM, "statm", S_IFREG|S_IRUGO),
+#ifdef SMP
+ E(PROC_PID_CPU, "cpu", S_IFREG|S_IRUGO),
+#endif
+#if CONFIG_AP1000
+ E(PROC_PID_RINGBUF, "ringbuf", S_IFREG|S_IRUGO|S_IWUSR),
#endif
+ E(PROC_PID_MAPS, "maps", S_IFREG|S_IRUGO),
+ E(PROC_PID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR),
+ E(PROC_PID_CWD, "cwd", S_IFLNK|S_IRWXUGO),
+ E(PROC_PID_ROOT, "root", S_IFLNK|S_IRWXUGO),
+ E(PROC_PID_EXE, "exe", S_IFLNK|S_IRWXUGO),
+ {0,0,NULL,0}
+};
+#undef E
+
+#define NUMBUF 10
+
+static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct task_struct *p = inode->u.proc_i.task;
+ unsigned int fd, pid, ino;
+ int retval;
+ char buf[NUMBUF];
+
+ retval = 0;
+ pid = p->pid;
+
+ fd = filp->f_pos;
+ switch (fd) {
+ case 0:
+ if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0)
+ goto out;
+ filp->f_pos++;
+ case 1:
+ ino = fake_ino(pid, PROC_PID_INO);
+ if (filldir(dirent, "..", 2, 1, ino) < 0)
+ goto out;
+ filp->f_pos++;
+ default:
+ for (fd = filp->f_pos-2;
+ p->p_pptr && p->files && fd < p->files->max_fds;
+ fd++, filp->f_pos++) {
+ unsigned int i,j;
+
+ if (!fcheck_task(p, fd))
+ continue;
+
+ j = NUMBUF;
+ i = fd;
+ do {
+ j--;
+ buf[j] = '0' + (i % 10);
+ i /= 10;
+ } while (i);
+
+ ino = fake_ino(pid, PROC_PID_FD_DIR + fd);
+ if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino) < 0)
+ break;
+
+ }
+ }
+out:
+ return retval;
+}
+
+static int proc_base_readdir(struct file * filp,
+ void * dirent, filldir_t filldir)
+{
+ int i;
+ int pid;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct pid_entry *p;
+
+ pid = inode->u.proc_i.task->pid;
+ if (!inode->u.proc_i.task->p_pptr)
+ return -ENOENT;
+ i = filp->f_pos;
+ switch (i) {
+ case 0:
+ if (filldir(dirent, ".", 1, i, inode->i_ino) < 0)
+ return 0;
+ i++;
+ filp->f_pos++;
+ /* fall through */
+ case 1:
+ if (filldir(dirent, "..", 2, i, PROC_ROOT_INO) < 0)
+ return 0;
+ i++;
+ filp->f_pos++;
+ /* fall through */
+ default:
+ i -= 2;
+ if (i>=sizeof(base_stuff)/sizeof(base_stuff[0]))
+ return 1;
+ p = base_stuff + i;
+ while (p->name) {
+ if (filldir(dirent, p->name, p->len, filp->f_pos, fake_ino(pid, p->type)) < 0)
+ return 0;
+ filp->f_pos++;
+ p++;
+ }
+ }
+ return 1;
+}
+
+/* building an inode */
+
+static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task, int ino)
+{
+ struct inode * inode;
+
+ /* We need a new inode */
+
+ inode = get_empty_inode();
+ if (!inode)
+ goto out;
+
+ /* Common stuff */
+
+ inode->i_sb = sb;
+ inode->i_dev = sb->s_dev;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_ino = fake_ino(task->pid, ino);
+
+ inode->u.proc_i.file = NULL;
+ /*
+ * grab the reference to task.
+ */
+ inode->u.proc_i.task = task;
+ atomic_inc(&mem_map[MAP_NR(task)].count);
+ if (!task->p_pptr)
+ goto out_unlock;
-#ifdef __SMP__
-static struct proc_dir_entry proc_pid_cpu = {
- PROC_PID_CPU, 3, "cpu",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
- NULL, proc_pid_fill_inode,
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+ if (ino == PROC_PID_INO || task->dumpable) {
+ inode->i_uid = task->euid;
+ inode->i_gid = task->egid;
+ }
+
+out:
+ return inode;
+
+out_unlock:
+ iput(inode);
+ return NULL;
+}
+
+/* dentry stuff */
+
+static int pid_fd_revalidate(struct dentry * dentry, int flags)
+{
+ return 0;
+}
+
+static int pid_base_revalidate(struct dentry * dentry, int flags)
+{
+ if (dentry->d_inode->u.proc_i.task->p_pptr)
+ return 1;
+ d_drop(dentry);
+ return 0;
+}
+
+static void pid_delete_dentry(struct dentry * dentry)
+{
+ d_drop(dentry);
+}
+
+static struct dentry_operations pid_fd_dentry_operations =
+{
+ pid_fd_revalidate, /* revalidate */
+ NULL, /* d_hash */
+ NULL, /* d_compare */
+ pid_delete_dentry /* d_delete(struct dentry *) */
+};
+
+static struct dentry_operations pid_dentry_operations =
+{
+ NULL, /* revalidate */
+ NULL, /* d_hash */
+ NULL, /* d_compare */
+ pid_delete_dentry /* d_delete(struct dentry *) */
+};
+
+static struct dentry_operations pid_base_dentry_operations =
+{
+ pid_base_revalidate, /* revalidate */
+ NULL, /* d_hash */
+ NULL, /* d_compare */
+ pid_delete_dentry /* d_delete(struct dentry *) */
+};
+
+/* Lookups */
+
+static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry)
+{
+ unsigned int fd, c;
+ struct task_struct *task = dir->u.proc_i.task;
+ struct file * file;
+ struct files_struct * files;
+ struct inode *inode;
+ const char *name;
+ int len;
+
+ fd = 0;
+ len = dentry->d_name.len;
+ name = dentry->d_name.name;
+ if (len > 1 && *name == '0') goto out;
+ while (len-- > 0) {
+ c = *name - '0';
+ name++;
+ if (c > 9)
+ goto out;
+ fd *= 10;
+ fd += c;
+ if (fd & 0xffff8000)
+ goto out;
+ }
+
+ inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_FD_DIR+fd);
+ if (!inode)
+ goto out;
+ /* FIXME */
+ files = task->files;
+ if (!files) /* can we ever get here if that's the case? */
+ goto out_unlock;
+ read_lock(&files->file_lock);
+ file = inode->u.proc_i.file = fcheck_task(task, fd);
+ if (!file)
+ goto out_unlock2;
+ get_file(file);
+ read_unlock(&files->file_lock);
+ inode->i_op = &proc_pid_link_inode_operations;
+ inode->i_size = 64;
+ inode->i_mode = S_IFLNK;
+ inode->u.proc_i.op.proc_get_link = proc_fd_link;
+ if (file->f_mode & 1)
+ inode->i_mode |= S_IRUSR | S_IXUSR;
+ if (file->f_mode & 2)
+ inode->i_mode |= S_IWUSR | S_IXUSR;
+ dentry->d_op = &pid_fd_dentry_operations;
+ d_add(dentry, inode);
+ return NULL;
+
+out_unlock2:
+ read_unlock(&files->file_lock);
+out_unlock:
+ iput(inode);
+out:
+ return ERR_PTR(-ENOENT);
+}
+
+static struct file_operations proc_fd_operations = {
+ NULL, /* lseek - default */
+ proc_dir_read, /* read - bad */
+ NULL, /* write - bad */
+ proc_readfd, /* readdir */
};
-#endif
-void __init proc_base_init(void)
+/*
+ * proc directories can do almost nothing..
+ */
+static struct inode_operations proc_fd_inode_operations = {
+ &proc_fd_operations, /* default base directory file-ops */
+ NULL, /* create */
+ proc_lookupfd, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* get_block */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* flushpage */
+ NULL, /* truncate */
+ proc_permission, /* permission */
+};
+
+static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
{
+ struct inode *inode;
+ int error;
+ struct task_struct *task = dir->u.proc_i.task;
+ struct pid_entry *p;
+
+ error = -ENOENT;
+ inode = NULL;
+
+ for (p = base_stuff; p->name; p++) {
+ if (p->len != dentry->d_name.len)
+ continue;
+ if (!memcmp(dentry->d_name.name, p->name, p->len))
+ break;
+ }
+ if (!p->name)
+ goto out;
+
+ error = -EINVAL;
+ inode = proc_pid_make_inode(dir->i_sb, task, p->type);
+ if (!inode)
+ goto out;
+
+ inode->i_mode = p->mode;
+ /*
+ * Yes, it does not scale. And it should not. Don't add
+ * new entries into /proc/<pid>/ without very good reasons.
+ */
+ switch(p->type) {
+ case PROC_PID_FD:
+ inode->i_nlink = 2;
+ inode->i_op = &proc_fd_inode_operations;
+ break;
+ case PROC_PID_EXE:
+ inode->i_op = &proc_pid_link_inode_operations;
+ inode->u.proc_i.op.proc_get_link = proc_exe_link;
+ break;
+ case PROC_PID_CWD:
+ inode->i_op = &proc_pid_link_inode_operations;
+ inode->u.proc_i.op.proc_get_link = proc_cwd_link;
+ break;
+ case PROC_PID_ROOT:
+ inode->i_op = &proc_pid_link_inode_operations;
+ inode->u.proc_i.op.proc_get_link = proc_root_link;
+ break;
+ case PROC_PID_ENVIRON:
+ inode->i_op = &proc_info_inode_operations;
+ inode->u.proc_i.op.proc_read = proc_pid_environ;
+ break;
+ case PROC_PID_STATUS:
+ inode->i_op = &proc_info_inode_operations;
+ inode->u.proc_i.op.proc_read = proc_pid_status;
+ break;
+ case PROC_PID_STAT:
+ inode->i_op = &proc_info_inode_operations;
+ inode->u.proc_i.op.proc_read = proc_pid_stat;
+ break;
+ case PROC_PID_CMDLINE:
+ inode->i_op = &proc_info_inode_operations;
+ inode->u.proc_i.op.proc_read = proc_pid_cmdline;
+ break;
+ case PROC_PID_STATM:
+ inode->i_op = &proc_info_inode_operations;
+ inode->u.proc_i.op.proc_read = proc_pid_statm;
+ break;
+ case PROC_PID_MAPS:
+ inode->i_op = &proc_maps_inode_operations;
+ break;
+#ifdef SMP
+ case PROC_PID_CPU:
+ inode->i_op = &proc_info_inode_operations;
+ inode->u.proc_i.op.proc_read = proc_pid_cpu;
+ break;
+#endif
#if CONFIG_AP1000
- proc_register(&proc_pid, &proc_pid_ringbuf);
+ case PROC_PID_RINGBUF:
+ inode->i_op = &proc_ringbuf_inode_operations;
+ break;
#endif
- proc_register(&proc_pid, &proc_pid_status);
- proc_register(&proc_pid, &proc_pid_mem);
- proc_register(&proc_pid, &proc_pid_cwd);
- proc_register(&proc_pid, &proc_pid_root);
- proc_register(&proc_pid, &proc_pid_exe);
- proc_register(&proc_pid, &proc_pid_fd);
- proc_register(&proc_pid, &proc_pid_environ);
- proc_register(&proc_pid, &proc_pid_cmdline);
- proc_register(&proc_pid, &proc_pid_stat);
- proc_register(&proc_pid, &proc_pid_statm);
- proc_register(&proc_pid, &proc_pid_maps);
-#ifdef __SMP__
- proc_register(&proc_pid, &proc_pid_cpu);
-#endif
+ case PROC_PID_MEM:
+ inode->i_op = &proc_mem_inode_operations;
+ break;
+ default:
+ printk("procfs: impossible type (%d)",p->type);
+ iput(inode);
+ return ERR_PTR(-EINVAL);
+ }
+ dentry->d_op = &pid_dentry_operations;
+ d_add(dentry, inode);
+ return NULL;
+
+out:
+ return ERR_PTR(error);
+}
+
+static struct file_operations proc_base_operations = {
+ NULL, /* lseek - default */
+ proc_dir_read, /* read - bad */
+ NULL, /* write - bad */
+ proc_base_readdir, /* readdir */
+};
+
+static struct inode_operations proc_base_inode_operations = {
+ &proc_base_operations, /* default base directory file-ops */
+ NULL, /* create */
+ proc_base_lookup, /* lookup */
};
+struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry)
+{
+ unsigned int pid, c;
+ struct task_struct *task;
+ const char *name;
+ struct inode *inode;
+ int len;
+
+ pid = 0;
+ name = dentry->d_name.name;
+ len = dentry->d_name.len;
+ while (len-- > 0) {
+ c = *name - '0';
+ name++;
+ if (c > 9)
+ goto out;
+ pid *= 10;
+ pid += c;
+ if (!pid)
+ goto out;
+ if (pid & 0xffff0000)
+ goto out;
+ }
+
+ read_lock(&tasklist_lock);
+ task = find_task_by_pid(pid);
+ if (task)
+ atomic_inc(&mem_map[MAP_NR(task)].count);
+ read_unlock(&tasklist_lock);
+ if (!task)
+ goto out;
+
+ inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_INO);
+
+ free_task_struct(task);
+ if (!inode)
+ goto out;
+ inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
+ inode->i_op = &proc_base_inode_operations;
+ inode->i_nlink = 3;
+ inode->i_flags|=S_IMMUTABLE;
+ dentry->d_op = &pid_base_dentry_operations;
+ d_add(dentry, inode);
+ return NULL;
+out:
+ return ERR_PTR(-ENOENT);
+}
+
+void proc_pid_delete_inode(struct inode *inode)
+{
+ if (inode->u.proc_i.file)
+ fput(inode->u.proc_i.file);
+ free_task_struct(inode->u.proc_i.task);
+}
+#define PROC_NUMBUF 10
+#define PROC_MAXPIDS 20
+
+/*
+ * Get a few pid's to return for filldir - we need to hold the
+ * tasklist lock while doing this, and we must release it before
+ * we actually do the filldir itself, so we use a temp buffer..
+ */
+static int get_pid_list(int index, unsigned int *pids)
+{
+ struct task_struct *p;
+ int nr_pids = 0;
+ index -= FIRST_PROCESS_ENTRY;
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ int pid = p->pid;
+ if (!pid)
+ continue;
+ if (--index >= 0)
+ continue;
+ pids[nr_pids] = pid;
+ nr_pids++;
+ if (nr_pids >= PROC_MAXPIDS)
+ break;
+ }
+ read_unlock(&tasklist_lock);
+ return nr_pids;
+}
+int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
+{
+ unsigned int pid_array[PROC_MAXPIDS];
+ char buf[PROC_NUMBUF];
+ unsigned int nr = filp->f_pos;
+ unsigned int nr_pids, i;
+ nr_pids = get_pid_list(nr, pid_array);
+ for (i = 0; i < nr_pids; i++) {
+ int pid = pid_array[i];
+ ino_t ino = fake_ino(pid,PROC_PID_INO);
+ unsigned long j = PROC_NUMBUF;
+ do {
+ j--;
+ buf[j] = '0' + (pid % 10);
+ pid /= 10;
+ } while (pid);
+ if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino) < 0)
+ break;
+ filp->f_pos++;
+ }
+ return 0;
+}
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
deleted file mode 100644
index 1862f6f5f..000000000
--- a/fs/proc/fd.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * linux/fs/proc/fd.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * proc fd directory handling functions
- *
- * 01-May-98 Edgar Toernig <froese@gmx.de>
- * Added support for more than 256 fds.
- * Limit raised to 32768.
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/file.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-
-#include <asm/uaccess.h>
-
-static int proc_readfd(struct file *, void *, filldir_t);
-static struct dentry *proc_lookupfd(struct inode *, struct dentry *);
-
-static struct file_operations proc_fd_operations = {
- NULL, /* lseek - default */
- NULL, /* read - bad */
- NULL, /* write - bad */
- proc_readfd, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-/*
- * proc directories can do almost nothing..
- */
-struct inode_operations proc_fd_inode_operations = {
- &proc_fd_operations, /* default base directory file-ops */
- NULL, /* create */
- proc_lookupfd, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- proc_permission, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-/*
- * NOTE! Normally we'd indicate that a file does not
- * exist by creating a negative dentry and returning
- * a successful return code. However, for this case
- * we do not want to create negative dentries, because
- * the state of the world can change behind our backs.
- *
- * Thus just return -ENOENT instead.
- */
-static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry)
-{
- unsigned int ino, pid, fd, c;
- struct task_struct * p;
- struct file * file;
- struct inode *inode;
- const char *name;
- int len, err;
-
- err = -ENOENT;
- ino = dir->i_ino;
- pid = ino >> 16;
- ino &= 0x0000ffff;
-
- if (!pid || ino != PROC_PID_FD)
- goto out;
-
- fd = 0;
- len = dentry->d_name.len;
- name = dentry->d_name.name;
- if (len > 1 && *name == '0') goto out;
- while (len-- > 0) {
- c = *name - '0';
- name++;
- if (c > 9)
- goto out;
- fd *= 10;
- fd += c;
- if (fd & 0xffff8000)
- goto out;
- }
-
- read_lock(&tasklist_lock);
- file = NULL;
- p = find_task_by_pid(pid);
- if (p && p->files)
- file = fcheck_task(p, fd);
- read_unlock(&tasklist_lock);
-
- /*
- * File handle is invalid if it is out of range, if the process
- * has no files (Zombie) if the file is closed, or if its inode
- * is NULL
- */
-
- if (!file)
- goto out;
-
- ino = (pid << 16) + PROC_PID_FD_DIR + fd;
- inode = proc_get_inode(dir->i_sb, ino, NULL);
- if (inode) {
- dentry->d_op = &proc_dentry_operations;
- d_add(dentry, inode);
- return NULL;
- }
-out:
- return ERR_PTR(err);
-}
-
-#define NUMBUF 10
-
-static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
-{
- struct inode *inode = filp->f_dentry->d_inode;
- struct task_struct *p, *tmp;
- unsigned int fd, pid, ino;
- int retval;
- char buf[NUMBUF];
-
- retval = 0;
- ino = inode->i_ino;
- pid = ino >> 16;
- ino &= 0x0000ffff;
- if (ino != PROC_PID_FD)
- goto out;
-
- for (fd = filp->f_pos; fd < 2; fd++, filp->f_pos++) {
- ino = inode->i_ino;
- if (fd)
- ino = (ino & 0xffff0000) | PROC_PID_INO;
- if (filldir(dirent, "..", fd+1, fd, ino) < 0)
- goto out;
- }
-
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- if (!p)
- goto out_unlock;
-
- for (fd -= 2 ; p->files && fd < p->files->max_fds; fd++, filp->f_pos++)
- {
- unsigned int i,j;
-
- if (!fcheck_task(p, fd))
- continue;
-
- j = NUMBUF;
- i = fd;
- do {
- j--;
- buf[j] = '0' + (i % 10);
- i /= 10;
- } while (i);
-
- /* Drop the task lock, as the filldir function may block */
- read_unlock(&tasklist_lock);
-
- ino = (pid << 16) + PROC_PID_FD_DIR + fd;
- if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino) < 0)
- goto out;
-
- read_lock(&tasklist_lock);
- /*
- * filldir() might have slept, so we must
- * re-validate "p". This is fast enough due
- * to the pidhash
- */
- tmp = find_task_by_pid(pid);
- if (p != tmp)
- break;
- }
-out_unlock:
- read_unlock(&tasklist_lock);
-
-out:
- return retval;
-}
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 1a2fe0f6e..5ef59004c 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -70,33 +70,6 @@ struct inode_operations proc_file_inode_operations = {
NULL /* revalidate */
};
-/*
- * compatibility to replace fs/proc/net.c
- */
-struct inode_operations proc_net_inode_operations = {
- &proc_file_operations, /* default net file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
diff --git a/fs/proc/inode-alloc.txt b/fs/proc/inode-alloc.txt
index 440d3baf8..4af79966c 100644
--- a/fs/proc/inode-alloc.txt
+++ b/fs/proc/inode-alloc.txt
@@ -1,50 +1,14 @@
-Inode allocations in the proc-fs (hex-numbers):
+Current inode allocations in the proc-fs (hex-numbers):
00000000 reserved
- 00000001-00000fff static entries
+ 00000001-00000fff static entries (goners)
001 root-ino
- 002 load-avg
- 003 uptime
- ...
- 080 net/*
- ...
- 100 scsi/*
- ...
- xxx mca/*
- ...
- yyy bus/*
- ...
- fff end
00001000-00001fff dynamic entries
-
00002000-00002fff openprom entries
-
0001xxxx-7fffxxxx pid-dir entries for pid 1-7fff
- 0000 unused
- 0001 unused
- 0002 pid
- 0003 pid/status
- ...
- 0008 pid/fd
- ...
- 00xx-00ff unused
- 01xx pid/fd/* for fd 0-ff
- ...
- 01ff end
- 0200-ffff unused
-
80000000-ffffffff unused
-
-
-New allocation:
-
- 00000000-0000ffff unchanged
-
- 0001xxxx-7fffxxxx pid-dir entries for pid 1-7fff
- 0000-00ff unchanged
- 0100-7fff unused
- 8000-ffff pid/fd/* for fd 0-7fff
-
- 80000000-ffffffff unchanged
+Goal:
+ a) once we'll split the thing into several virtual filesystems we
+ will get rid of magical ranges (and this file, BTW).
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index a5596e4ee..8842cc253 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -14,6 +14,7 @@
#include <linux/locks.h>
#include <linux/limits.h>
#include <linux/config.h>
+#include <linux/module.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -51,9 +52,7 @@ void de_put(struct proc_dir_entry *de)
static void proc_put_inode(struct inode *inode)
{
#ifdef CONFIG_SUN_OPENPROMFS_MODULE
- if ((inode->i_ino >= PROC_OPENPROM_FIRST) &&
- (inode->i_ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM) &&
- proc_openprom_use)
+ if (PROC_INODE_OPENPROM(inode) && proc_openprom_use)
(*proc_openprom_use)(inode, 0);
#endif
/*
@@ -71,18 +70,16 @@ static void proc_delete_inode(struct inode *inode)
{
struct proc_dir_entry *de = inode->u.generic_ip;
-#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
- if ((inode->i_ino >= PROC_OPENPROM_FIRST) &&
- (inode->i_ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM))
+ if (PROC_INODE_PROPER(inode)) {
+ proc_pid_delete_inode(inode);
+ return;
+ }
+ if (PROC_INODE_OPENPROM(inode))
return;
-#endif
if (de) {
- /*
- * Call the fill_inode hook to release module counts.
- */
- if (de->fill_inode)
- de->fill_inode(inode, 0);
+ if (de->owner)
+ __MOD_DEC_USE_COUNT(de->owner);
de_put(de);
}
}
@@ -142,113 +139,6 @@ static int parse_options(char *options,uid_t *uid,gid_t *gid)
return 1;
}
-/*
- * The standard rules, copied from fs/namei.c:permission().
- */
-static int standard_permission(struct inode *inode, int mask)
-{
- int mode = inode->i_mode;
-
- if ((mask & S_IWOTH) && IS_RDONLY(inode) &&
- (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
- return -EROFS; /* Nobody gets write access to a read-only fs */
- else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
- return -EACCES; /* Nobody gets write access to an immutable file */
- else if (current->fsuid == inode->i_uid)
- mode >>= 6;
- else if (in_group_p(inode->i_gid))
- mode >>= 3;
- if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE))
- return 0;
- /* read and search access */
- if ((mask == S_IROTH) ||
- (S_ISDIR(mode) && !(mask & ~(S_IROTH | S_IXOTH))))
- if (capable(CAP_DAC_READ_SEARCH))
- return 0;
- return -EACCES;
-}
-
-/*
- * Set up permission rules for processes looking at other processes.
- * You're not allowed to see a process unless it has the same or more
- * restricted root than your own. This prevents a chrooted processes
- * from escaping through the /proc entries of less restricted
- * processes, and thus allows /proc to be safely mounted in a chrooted
- * area.
- *
- * Note that root (uid 0) doesn't get permission for this either,
- * since chroot is stronger than root.
- *
- * XXX TODO: use the dentry mechanism to make off-limits procs simply
- * invisible rather than denied? Does each namespace root get its own
- * dentry tree?
- *
- * This also applies the default permissions checks, as it only adds
- * restrictions.
- *
- * Jeremy Fitzhardinge <jeremy@zip.com.au>
- */
-int proc_permission(struct inode *inode, int mask)
-{
- struct task_struct *p;
- unsigned long ino = inode->i_ino;
- unsigned long pid;
- struct dentry *de, *base;
-
- if (standard_permission(inode, mask) != 0)
- return -EACCES;
-
- /*
- * Find the root of the processes being examined (if any).
- * XXX Surely there's a better way of doing this?
- */
- if (ino >= PROC_OPENPROM_FIRST &&
- ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM)
- return 0; /* already allowed */
-
- pid = ino >> 16;
- if (pid == 0)
- return 0; /* already allowed */
-
- de = NULL;
- base = current->fs->root;
-
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
-
- if (p && p->fs)
- de = p->fs->root;
- read_unlock(&tasklist_lock); /* FIXME! */
-
- if (p == NULL)
- return -EACCES; /* ENOENT? */
-
- if (de == NULL)
- {
- /* kswapd and bdflush don't have proper root or cwd... */
- return -EACCES;
- }
-
- /* XXX locking? */
- for(;;)
- {
- struct dentry *parent;
-
- if (de == base)
- return 0; /* already allowed */
-
- de = de->d_covers;
- parent = de->d_parent;
-
- if (de == parent)
- break;
-
- de = parent;
- }
-
- return -EACCES; /* incompatible roots */
-}
-
struct inode * proc_get_inode(struct super_block * sb, int ino,
struct proc_dir_entry * de)
{
@@ -269,14 +159,9 @@ printk("proc_iget: using deleted entry %s, count=%d\n", de->name, de->count);
goto out_fail;
#ifdef CONFIG_SUN_OPENPROMFS_MODULE
- if ((inode->i_ino >= PROC_OPENPROM_FIRST)
- && (inode->i_ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM)
- && proc_openprom_use)
+ if (PROC_INODE_OPENPROM(inode) && proc_openprom_use)
(*proc_openprom_use)(inode, 1);
#endif
- /* N.B. How can this test ever fail?? */
- if (inode->i_sb != sb)
- printk("proc_get_inode: inode fubar\n");
inode->u.generic_ip = (void *) de;
if (de) {
@@ -291,12 +176,8 @@ printk("proc_iget: using deleted entry %s, count=%d\n", de->name, de->count);
inode->i_op = de->ops;
if (de->nlink)
inode->i_nlink = de->nlink;
- /*
- * The fill_inode routine should use this call
- * to increment module counts, if necessary.
- */
- if (de->fill_inode)
- de->fill_inode(inode, 1);
+ if (de->owner)
+ __MOD_INC_USE_COUNT(de->owner);
}
/*
* Fixup the root inode's nlink value
@@ -366,63 +247,7 @@ int proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
void proc_read_inode(struct inode * inode)
{
- unsigned long ino, pid;
- struct task_struct * p;
-
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_blocks = 0;
- inode->i_blksize = 1024;
- ino = inode->i_ino;
- if (ino >= PROC_OPENPROM_FIRST &&
- ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM)
- goto out;
- inode->i_op = NULL;
- inode->i_mode = 0;
- inode->i_uid = 0;
- inode->i_gid = 0;
- inode->i_nlink = 1;
- inode->i_size = 0;
-
- pid = ino >> 16;
- if (!pid)
- goto out;
-
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- if (!p)
- goto out_unlock;
-
- ino &= 0x0000ffff;
- if (ino == PROC_PID_INO || p->dumpable) {
- inode->i_uid = p->euid;
- inode->i_gid = p->egid;
- }
- if (ino & PROC_PID_FD_DIR) {
- struct file * file;
- ino &= 0x7fff;
- if (!p->files) /* can we ever get here if that's the case? */
- goto out_unlock;
- read_lock(&p->files->file_lock);
- file = fcheck_task(p, ino);
- if (!file)
- goto out_unlock2;
-
- inode->i_op = &proc_link_inode_operations;
- inode->i_size = 64;
- inode->i_mode = S_IFLNK;
- if (file->f_mode & 1)
- inode->i_mode |= S_IRUSR | S_IXUSR;
- if (file->f_mode & 2)
- inode->i_mode |= S_IWUSR | S_IXUSR;
-out_unlock2:
- read_unlock(&p->files->file_lock);
- }
-out_unlock:
- /* Defer unlocking until we're done with the task */
- read_unlock(&tasklist_lock);
-
-out:
- return;
}
void proc_write_inode(struct inode * inode)
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
new file mode 100644
index 000000000..ec2a92db3
--- /dev/null
+++ b/fs/proc/kcore.c
@@ -0,0 +1,388 @@
+/*
+ * fs/proc/kcore.c kernel ELF/AOUT core dumper
+ *
+ * Modelled on fs/exec.c:aout_core_dump()
+ * Jeremy Fitzhardinge <jeremy@sw.oz.au>
+ * Implemented by David Howells <David.Howells@nexor.co.uk>
+ * Modified and incorporated into 2.3.x by Tigran Aivazian <tigran@sco.com>
+ * Support to dump vmalloc'd data structures (ELF only), Tigran Aivazian <tigran@sco.com>
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/elf.h>
+#include <linux/elfcore.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+
+
+static int open_kcore(struct inode * inode, struct file * filp)
+{
+ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+}
+
+static ssize_t read_kcore(struct file *, char *, size_t, loff_t *);
+
+static struct file_operations proc_kcore_operations = {
+ NULL, /* lseek */
+ read_kcore,
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ open_kcore
+};
+
+struct inode_operations proc_kcore_inode_operations = {
+ &proc_kcore_operations,
+};
+
+#ifdef CONFIG_KCORE_AOUT
+static ssize_t read_kcore(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned long long p = *ppos, memsize;
+ ssize_t read;
+ ssize_t count1;
+ char * pnt;
+ struct user dump;
+#if defined (__i386__) || defined (__mc68000__)
+# define FIRST_MAPPED PAGE_SIZE /* we don't have page 0 mapped on x86.. */
+#else
+# define FIRST_MAPPED 0
+#endif
+
+ memset(&dump, 0, sizeof(struct user));
+ dump.magic = CMAGIC;
+ dump.u_dsize = max_mapnr;
+#if defined (__i386__)
+ dump.start_code = PAGE_OFFSET;
+#endif
+#ifdef __alpha__
+ dump.start_data = PAGE_OFFSET;
+#endif
+
+ memsize = (max_mapnr + 1) << PAGE_SHIFT;
+ if (p >= memsize)
+ return 0;
+ if (count > memsize - p)
+ count = memsize - p;
+ read = 0;
+
+ if (p < sizeof(struct user) && count > 0) {
+ count1 = count;
+ if (p + count1 > sizeof(struct user))
+ count1 = sizeof(struct user)-p;
+ pnt = (char *) &dump + p;
+ copy_to_user(buf,(void *) pnt, count1);
+ buf += count1;
+ p += count1;
+ count -= count1;
+ read += count1;
+ }
+
+ if (count > 0 && p < PAGE_SIZE + FIRST_MAPPED) {
+ count1 = PAGE_SIZE + FIRST_MAPPED - p;
+ if (count1 > count)
+ count1 = count;
+ clear_user(buf, count1);
+ buf += count1;
+ p += count1;
+ count -= count1;
+ read += count1;
+ }
+ if (count > 0) {
+ copy_to_user(buf, (void *) (PAGE_OFFSET+p-PAGE_SIZE), count);
+ read += count;
+ }
+ *ppos += read;
+ return read;
+}
+#else /* CONFIG_KCORE_AOUT */
+
+#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+
+/* An ELF note in memory */
+struct memelfnote
+{
+ const char *name;
+ int type;
+ unsigned int datasz;
+ void *data;
+};
+
+extern char saved_command_line[];
+
+static size_t get_kcore_size(int *num_vma, int *elf_buflen)
+{
+ size_t try, size = 0;
+ struct vm_struct *m;
+
+ *num_vma = 0;
+ if (!vmlist) {
+ *elf_buflen = PAGE_SIZE;
+ return ((size_t)high_memory - PAGE_OFFSET + PAGE_SIZE);
+ }
+
+ for (m=vmlist; m; m=m->next) {
+ try = (size_t)m->addr + m->size;
+ if (try > size)
+ size = try;
+ *num_vma = *num_vma + 1;
+ }
+ *elf_buflen = sizeof(struct elfhdr) +
+ (*num_vma + 2)*sizeof(struct elf_phdr) +
+ 3 * sizeof(struct memelfnote);
+ *elf_buflen = PAGE_ALIGN(*elf_buflen);
+ return (size - PAGE_OFFSET + *elf_buflen);
+}
+
+
+/*****************************************************************************/
+/*
+ * determine size of ELF note
+ */
+static int notesize(struct memelfnote *en)
+{
+ int sz;
+
+ sz = sizeof(struct elf_note);
+ sz += roundup(strlen(en->name), 4);
+ sz += roundup(en->datasz, 4);
+
+ return sz;
+} /* end notesize() */
+
+/*****************************************************************************/
+/*
+ * store a note in the header buffer
+ */
+static char *storenote(struct memelfnote *men, char *bufp)
+{
+ struct elf_note en;
+
+#define DUMP_WRITE(addr,nr) do { memcpy(bufp,addr,nr); bufp += nr; } while(0)
+
+ en.n_namesz = strlen(men->name);
+ en.n_descsz = men->datasz;
+ en.n_type = men->type;
+
+ DUMP_WRITE(&en, sizeof(en));
+ DUMP_WRITE(men->name, en.n_namesz);
+
+ /* XXX - cast from long long to long to avoid need for libgcc.a */
+ bufp = (char*) roundup((unsigned long)bufp,4);
+ DUMP_WRITE(men->data, men->datasz);
+ bufp = (char*) roundup((unsigned long)bufp,4);
+
+#undef DUMP_WRITE
+
+ return bufp;
+} /* end storenote() */
+
+/*
+ * store an ELF coredump header in the supplied buffer
+ * num_vma is the number of elements in vmlist
+ */
+static void elf_kcore_store_hdr(char *bufp, int num_vma, int elf_buflen)
+{
+ struct elf_prstatus prstatus; /* NT_PRSTATUS */
+ struct elf_prpsinfo prpsinfo; /* NT_PRPSINFO */
+ struct elf_phdr *nhdr, *phdr;
+ struct elfhdr *elf;
+ struct memelfnote notes[3];
+ off_t offset = 0;
+ struct vm_struct *m;
+
+ /* setup ELF header */
+ elf = (struct elfhdr *) bufp;
+ bufp += sizeof(struct elfhdr);
+ offset += sizeof(struct elfhdr);
+ memcpy(elf->e_ident, ELFMAG, SELFMAG);
+ elf->e_ident[EI_CLASS] = ELF_CLASS;
+ elf->e_ident[EI_DATA] = ELF_DATA;
+ elf->e_ident[EI_VERSION]= EV_CURRENT;
+ memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+ elf->e_type = ET_CORE;
+ elf->e_machine = ELF_ARCH;
+ elf->e_version = EV_CURRENT;
+ elf->e_entry = 0;
+ elf->e_phoff = sizeof(struct elfhdr);
+ elf->e_shoff = 0;
+ elf->e_flags = 0;
+ elf->e_ehsize = sizeof(struct elfhdr);
+ elf->e_phentsize= sizeof(struct elf_phdr);
+ elf->e_phnum = 2 + num_vma;
+ elf->e_shentsize= 0;
+ elf->e_shnum = 0;
+ elf->e_shstrndx = 0;
+
+ /* setup ELF PT_NOTE program header */
+ nhdr = (struct elf_phdr *) bufp;
+ bufp += sizeof(struct elf_phdr);
+ offset += sizeof(struct elf_phdr);
+ nhdr->p_type = PT_NOTE;
+ nhdr->p_offset = 0;
+ nhdr->p_vaddr = 0;
+ nhdr->p_paddr = 0;
+ nhdr->p_filesz = 0;
+ nhdr->p_memsz = 0;
+ nhdr->p_flags = 0;
+ nhdr->p_align = 0;
+
+ /* setup ELF PT_LOAD program header */
+ phdr = (struct elf_phdr *) bufp;
+ bufp += sizeof(struct elf_phdr);
+ offset += sizeof(struct elf_phdr);
+ phdr->p_type = PT_LOAD;
+ phdr->p_flags = PF_R|PF_W|PF_X;
+ phdr->p_offset = elf_buflen;
+ phdr->p_vaddr = PAGE_OFFSET;
+ phdr->p_paddr = __pa(PAGE_OFFSET);
+ phdr->p_filesz = phdr->p_memsz = ((unsigned long)high_memory - PAGE_OFFSET);
+ phdr->p_align = PAGE_SIZE;
+
+ for (m=vmlist; m; m=m->next) {
+ phdr = (struct elf_phdr *) bufp;
+ bufp += sizeof(struct elf_phdr);
+ offset += sizeof(struct elf_phdr);
+
+ phdr->p_type = PT_LOAD;
+ phdr->p_flags = PF_R|PF_W|PF_X;
+ phdr->p_offset = (size_t)m->addr - PAGE_OFFSET + elf_buflen;
+ phdr->p_vaddr = (size_t)m->addr;
+ phdr->p_paddr = __pa(m);
+ phdr->p_filesz = phdr->p_memsz = m->size;
+ phdr->p_align = PAGE_SIZE;
+ }
+
+ /*
+ * Set up the notes in similar form to SVR4 core dumps made
+ * with info from their /proc.
+ */
+ nhdr->p_offset = offset;
+
+ /* set up the process status */
+ notes[0].name = "CORE";
+ notes[0].type = NT_PRSTATUS;
+ notes[0].datasz = sizeof(struct elf_prstatus);
+ notes[0].data = &prstatus;
+
+ memset(&prstatus, 0, sizeof(struct elf_prstatus));
+
+ nhdr->p_filesz = notesize(&notes[0]);
+ bufp = storenote(&notes[0], bufp);
+
+ /* set up the process info */
+ notes[1].name = "CORE";
+ notes[1].type = NT_PRPSINFO;
+ notes[1].datasz = sizeof(struct elf_prpsinfo);
+ notes[1].data = &prpsinfo;
+
+ memset(&prpsinfo, 0, sizeof(struct elf_prpsinfo));
+ prpsinfo.pr_state = 0;
+ prpsinfo.pr_sname = 'R';
+ prpsinfo.pr_zomb = 0;
+
+ strcpy(prpsinfo.pr_fname, "vmlinux");
+ strncpy(prpsinfo.pr_psargs, saved_command_line, ELF_PRARGSZ);
+
+ nhdr->p_filesz = notesize(&notes[1]);
+ bufp = storenote(&notes[1], bufp);
+
+ /* set up the task structure */
+ notes[2].name = "CORE";
+ notes[2].type = NT_TASKSTRUCT;
+ notes[2].datasz = sizeof(struct task_struct);
+ notes[2].data = current;
+
+ nhdr->p_filesz = notesize(&notes[2]);
+ bufp = storenote(&notes[2], bufp);
+
+} /* end elf_kcore_store_hdr() */
+
+/*****************************************************************************/
+/*
+ * read from the ELF header and then kernel memory
+ */
+static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen,
+ loff_t *fpos)
+{
+ ssize_t acc = 0;
+ size_t size, tsz;
+ char * elf_buffer;
+ int elf_buflen = 0, num_vma = 0;
+
+ /* XXX we need to somehow lock vmlist between here
+ * and after elf_kcore_store_hdr() returns.
+ * For now assume that num_vma does not change (TA)
+ */
+ proc_root_kcore.size = size = get_kcore_size(&num_vma, &elf_buflen);
+ if (buflen == 0 || *fpos >= size)
+ return 0;
+
+ /* trim buflen to not go beyond EOF */
+ if (buflen > size - *fpos)
+ buflen = size - *fpos;
+
+ /* construct an ELF core header if we'll need some of it */
+ if (*fpos < elf_buflen) {
+ tsz = elf_buflen - *fpos;
+ if (buflen < tsz)
+ tsz = buflen;
+ elf_buffer = kmalloc(elf_buflen, GFP_KERNEL);
+ if (!elf_buffer)
+ return -ENOMEM;
+ memset(elf_buffer, 0, elf_buflen);
+ elf_kcore_store_hdr(elf_buffer, num_vma, elf_buflen);
+ copy_to_user(buffer, elf_buffer, tsz);
+ kfree(elf_buffer);
+ buflen -= tsz;
+ *fpos += tsz;
+ buffer += tsz;
+ acc += tsz;
+
+ /* leave now if filled buffer already */
+ if (buflen == 0)
+ return tsz;
+ }
+
+ /* where page 0 not mapped, write zeros into buffer */
+#if defined (__i386__) || defined (__mc68000__)
+ if (*fpos < PAGE_SIZE + elf_buflen) {
+ /* work out how much to clear */
+ tsz = PAGE_SIZE + elf_buflen - *fpos;
+ if (buflen < tsz)
+ tsz = buflen;
+
+ /* write zeros to buffer */
+ clear_user(buffer, tsz);
+ buflen -= tsz;
+ *fpos += tsz;
+ buffer += tsz;
+ acc += tsz;
+
+ /* leave now if filled buffer already */
+ if (buflen == 0)
+ return tsz;
+ }
+#endif
+
+ /* fill the remainder of the buffer from kernel VM space */
+#if defined (__i386__) || defined (__mc68000__)
+ copy_to_user(buffer, __va(*fpos - PAGE_SIZE), buflen);
+#else
+ copy_to_user(buffer, __va(*fpos), buflen);
+#endif
+ acc += buflen;
+ *fpos += buflen;
+
+ return acc;
+
+}
+#endif /* CONFIG_KCORE_AOUT */
diff --git a/fs/proc/link.c b/fs/proc/link.c
deleted file mode 100644
index 69d435600..000000000
--- a/fs/proc/link.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * linux/fs/proc/link.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * /proc link-file handling code
- */
-
-#include <asm/uaccess.h>
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-
-static int proc_readlink(struct dentry *, char *, int);
-static struct dentry * proc_follow_link(struct dentry *, struct dentry *, unsigned int);
-
-/*
- * links can't do much...
- */
-static struct file_operations proc_fd_link_operations = {
- NULL, /* lseek - default */
- NULL, /* read - bad */
- NULL, /* write - bad */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* very special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-struct inode_operations proc_link_inode_operations = {
- &proc_fd_link_operations,/* file-operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- proc_readlink, /* readlink */
- proc_follow_link, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- proc_permission, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-static struct dentry * proc_follow_link(struct dentry *dentry,
- struct dentry *base,
- unsigned int follow)
-{
- struct inode *inode = dentry->d_inode;
- struct task_struct *p;
- struct dentry * result;
- int ino, pid;
- int error;
-
- /* We don't need a base pointer in the /proc filesystem */
- dput(base);
-
- error = permission(inode, MAY_EXEC);
- result = ERR_PTR(error);
- if (error)
- goto out;
-
- ino = inode->i_ino;
- pid = ino >> 16;
- ino &= 0x0000ffff;
-
- result = ERR_PTR(-ENOENT);
-
- switch (ino) {
- case PROC_PID_CWD:
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- if (p && p->fs && p->fs->pwd)
- result = dget(p->fs->pwd);
- read_unlock(&tasklist_lock);
- break;
-
- case PROC_PID_ROOT:
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- if (p && p->fs && p->fs->root)
- result = dget(p->fs->root);
- read_unlock(&tasklist_lock);
- break;
-
- case PROC_PID_EXE: {
- struct mm_struct *mm = NULL;
- struct vm_area_struct * vma;
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- if (p)
- mm = p->mm;
- if (mm)
- atomic_inc(&mm->mm_users);
- read_unlock(&tasklist_lock);
- if (!mm)
- break;
- down(&mm->mmap_sem);
- vma = mm->mmap;
- while (vma) {
- if ((vma->vm_flags & VM_EXECUTABLE) &&
- vma->vm_file) {
- result = dget(vma->vm_file->f_dentry);
- break;
- }
- vma = vma->vm_next;
- }
- up(&mm->mmap_sem);
- mmput(mm);
- break;
- }
- default:
- if (ino & PROC_PID_FD_DIR) {
- struct file * file;
- struct files_struct *files = NULL;
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- if (p)
- files = p->files;
- read_unlock(&tasklist_lock);
- if (!files)
- break;
- ino &= 0x7fff;
- read_lock(&files->file_lock);
- /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
- if (ino < files->max_fds &&
- (file = files->fd[ino]) && file->f_dentry)
- result = dget(file->f_dentry);
- read_unlock(&p->files->file_lock);
- }
- }
-out:
- return result;
-}
-
-/*
- * This pretty-prints the pathname of a dentry,
- * clarifying sockets etc.
- */
-static int do_proc_readlink(struct dentry *dentry, char * buffer, int buflen)
-{
- struct inode * inode;
- char * tmp = (char*)__get_free_page(GFP_KERNEL), *path, *pattern;
- int len;
-
- if(tmp==NULL)
- return -ENOMEM;
-
- /* Check for special dentries.. */
- pattern = NULL;
- inode = dentry->d_inode;
- if (inode && IS_ROOT(dentry)) {
- if (S_ISSOCK(inode->i_mode))
- pattern = "socket:[%lu]";
- if (S_ISFIFO(inode->i_mode))
- pattern = "pipe:[%lu]";
- }
-
- if (pattern) {
- len = sprintf(tmp, pattern, inode->i_ino);
- path = tmp;
- } else {
- path = d_path(dentry, tmp, PAGE_SIZE);
- len = tmp + PAGE_SIZE - 1 - path;
- }
-
- if (len < buflen)
- buflen = len;
- dput(dentry);
- copy_to_user(buffer, path, buflen);
- free_page((unsigned long)tmp);
- return buflen;
-}
-
-static int proc_readlink(struct dentry * dentry, char * buffer, int buflen)
-{
- int error;
-
- dentry = proc_follow_link(dentry, NULL, 1);
- error = PTR_ERR(dentry);
- if (!IS_ERR(dentry)) {
- error = -ENOENT;
- if (dentry) {
- error = do_proc_readlink(dentry, buffer, buflen);
- }
- }
- return error;
-}
diff --git a/fs/proc/mem.c b/fs/proc/mem.c
deleted file mode 100644
index 90cd79722..000000000
--- a/fs/proc/mem.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * linux/fs/proc/mem.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/proc_fs.h>
-#include <linux/highmem.h>
-
-#include <asm/page.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-
-/*
- * mem_write isn't really a good idea right now. It needs
- * to check a lot more: if the process we try to write to
- * dies in the middle right now, mem_write will overwrite
- * kernel memory.. This disables it altogether.
- */
-#define mem_write NULL
-
-static int check_range(struct mm_struct * mm, unsigned long addr, int count)
-{
- struct vm_area_struct *vma;
- int retval;
-
- vma = find_vma(mm, addr);
- if (!vma)
- return -EACCES;
- if (vma->vm_start > addr)
- return -EACCES;
- if (!(vma->vm_flags & VM_READ))
- return -EACCES;
- while ((retval = vma->vm_end - addr) < count) {
- struct vm_area_struct *next = vma->vm_next;
- if (!next)
- break;
- if (vma->vm_end != next->vm_start)
- break;
- if (!(next->vm_flags & VM_READ))
- break;
- vma = next;
- }
- if (retval > count)
- retval = count;
- return retval;
-}
-
-static struct task_struct * get_task(int pid)
-{
- struct task_struct * tsk = current;
-
- if (pid != tsk->pid) {
- tsk = find_task_by_pid(pid);
-
- /* Allow accesses only under the same circumstances
- * that we would allow ptrace to work.
- */
- if (tsk) {
- if (!(tsk->flags & PF_PTRACED)
- || tsk->state != TASK_STOPPED
- || tsk->p_pptr != current)
- tsk = NULL;
- }
- }
- return tsk;
-}
-
-static ssize_t mem_read(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- struct inode * inode = file->f_dentry->d_inode;
- pgd_t *page_dir;
- pmd_t *page_middle;
- pte_t pte;
- struct page * page;
- struct task_struct * tsk;
- unsigned long addr;
- unsigned long maddr; /* temporary mapped address */
- char *tmp;
- ssize_t scount, i;
-
- read_lock(&tasklist_lock);
- tsk = get_task(inode->i_ino >> 16);
- read_unlock(&tasklist_lock); /* FIXME: This should really be done only afetr not using tsk any more!!! */
- if (!tsk)
- return -ESRCH;
- addr = *ppos;
- scount = check_range(tsk->mm, addr, count);
- if (scount < 0)
- return scount;
- tmp = buf;
- while (scount > 0) {
- if (signal_pending(current))
- break;
- page_dir = pgd_offset(tsk->mm,addr);
- if (pgd_none(*page_dir))
- break;
- if (pgd_bad(*page_dir)) {
- pgd_ERROR(*page_dir);
- pgd_clear(page_dir);
- break;
- }
- page_middle = pmd_offset(page_dir,addr);
- if (pmd_none(*page_middle))
- break;
- if (pmd_bad(*page_middle)) {
- pmd_ERROR(*page_middle);
- pmd_clear(page_middle);
- break;
- }
- pte = *pte_offset(page_middle,addr);
- if (!pte_present(pte))
- break;
- page = pte_page(pte);
- i = PAGE_SIZE-(addr & ~PAGE_MASK);
- if (i > scount)
- i = scount;
- maddr = kmap(page, KM_READ);
- copy_to_user(tmp, (char *)maddr + (addr & ~PAGE_MASK), i);
- kunmap(maddr, KM_READ);
- addr += i;
- tmp += i;
- scount -= i;
- }
- *ppos = addr;
- return tmp-buf;
-}
-
-#ifndef mem_write
-
-static ssize_t mem_write(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- struct inode * inode = file->f_dentry->d_inode;
- pgd_t *page_dir;
- pmd_t *page_middle;
- pte_t pte;
- struct page * page;
- struct task_struct * tsk;
- unsigned long addr;
- unsigned long maddr; /* temporary mapped address */
- char *tmp;
- long i;
-
- addr = *ppos;
- tsk = get_task(inode->i_ino >> 16);
- if (!tsk)
- return -ESRCH;
- tmp = buf;
- while (count > 0) {
- if (signal_pending(current))
- break;
- page_dir = pgd_offset(tsk,addr);
- if (pgd_none(*page_dir))
- break;
- if (pgd_bad(*page_dir)) {
- pgd_ERROR(*page_dir);
- pgd_clear(page_dir);
- break;
- }
- page_middle = pmd_offset(page_dir,addr);
- if (pmd_none(*page_middle))
- break;
- if (pmd_bad(*page_middle)) {
- pmd_ERROR(*page_middle);
- pmd_clear(page_middle);
- break;
- }
- pte = *pte_offset(page_middle,addr);
- if (!pte_present(pte))
- break;
- if (!pte_write(pte))
- break;
- page = pte_page(pte);
- i = PAGE_SIZE-(addr & ~PAGE_MASK);
- if (i > count)
- i = count;
- maddr = kmap(page, KM_WRITE);
- copy_from_user((char *)maddr + (addr & ~PAGE_MASK), tmp, i);
- kunmap(maddr, KM_WRITE);
- addr += i;
- tmp += i;
- count -= i;
- }
- *ppos = addr;
- if (tmp != buf)
- return tmp-buf;
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-#endif
-
-static long long mem_lseek(struct file * file, long long offset, int orig)
-{
- switch (orig) {
- case 0:
- file->f_pos = offset;
- return file->f_pos;
- case 1:
- file->f_pos += offset;
- return file->f_pos;
- default:
- return -EINVAL;
- }
-}
-
-/*
- * This isn't really reliable by any means..
- */
-int mem_mmap(struct file * file, struct vm_area_struct * vma)
-{
- struct task_struct *tsk;
- pgd_t *src_dir, *dest_dir;
- pmd_t *src_middle, *dest_middle;
- pte_t *src_table, *dest_table;
- unsigned long stmp, dtmp, mapnr;
- struct vm_area_struct *src_vma = NULL;
- struct inode *inode = file->f_dentry->d_inode;
-
- /* Get the source's task information */
-
- tsk = get_task(inode->i_ino >> 16);
-
- if (!tsk)
- return -ESRCH;
-
- /* Ensure that we have a valid source area. (Has to be mmap'ed and
- have valid page information.) We can't map shared memory at the
- moment because working out the vm_area_struct & nattach stuff isn't
- worth it. */
-
- src_vma = tsk->mm->mmap;
- stmp = vma->vm_offset;
- while (stmp < vma->vm_offset + (vma->vm_end - vma->vm_start)) {
- while (src_vma && stmp > src_vma->vm_end)
- src_vma = src_vma->vm_next;
- if (!src_vma || (src_vma->vm_flags & VM_SHM))
- return -EINVAL;
-
- src_dir = pgd_offset(tsk->mm, stmp);
- if (pgd_none(*src_dir))
- return -EINVAL;
- if (pgd_bad(*src_dir)) {
- pgd_ERROR(*src_dir);
- return -EINVAL;
- }
- src_middle = pmd_offset(src_dir, stmp);
- if (pmd_none(*src_middle))
- return -EINVAL;
- if (pmd_bad(*src_middle)) {
- pmd_ERROR(*src_middle);
- return -EINVAL;
- }
- src_table = pte_offset(src_middle, stmp);
- if (pte_none(*src_table))
- return -EINVAL;
-
- if (stmp < src_vma->vm_start) {
- if (!(src_vma->vm_flags & VM_GROWSDOWN))
- return -EINVAL;
- if (src_vma->vm_end - stmp > current->rlim[RLIMIT_STACK].rlim_cur)
- return -EINVAL;
- }
- stmp += PAGE_SIZE;
- }
-
- src_vma = tsk->mm->mmap;
- stmp = vma->vm_offset;
- dtmp = vma->vm_start;
-
- flush_cache_range(vma->vm_mm, vma->vm_start, vma->vm_end);
- flush_cache_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end);
- while (dtmp < vma->vm_end) {
- while (src_vma && stmp > src_vma->vm_end)
- src_vma = src_vma->vm_next;
-
- src_dir = pgd_offset(tsk->mm, stmp);
- src_middle = pmd_offset(src_dir, stmp);
- src_table = pte_offset(src_middle, stmp);
-
- dest_dir = pgd_offset(current->mm, dtmp);
- dest_middle = pmd_alloc(dest_dir, dtmp);
- if (!dest_middle)
- return -ENOMEM;
- dest_table = pte_alloc(dest_middle, dtmp);
- if (!dest_table)
- return -ENOMEM;
-
- if (!pte_present(*src_table))
- handle_mm_fault(tsk, src_vma, stmp, 1);
-
- if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table))
- handle_mm_fault(tsk, src_vma, stmp, 1);
-
- set_pte(src_table, pte_mkdirty(*src_table));
- set_pte(dest_table, *src_table);
- mapnr = pte_pagenr(*src_table);
- if (mapnr < max_mapnr)
- get_page(mem_map + pte_pagenr(*src_table));
-
- stmp += PAGE_SIZE;
- dtmp += PAGE_SIZE;
- }
-
- flush_tlb_range(vma->vm_mm, vma->vm_start, vma->vm_end);
- flush_tlb_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end);
- return 0;
-}
-
-static struct file_operations proc_mem_operations = {
- mem_lseek,
- mem_read,
- mem_write,
- NULL, /* mem_readdir */
- NULL, /* mem_poll */
- NULL, /* mem_ioctl */
- mem_mmap, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-struct inode_operations proc_mem_inode_operations = {
- &proc_mem_operations, /* default base directory file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- proc_permission, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
diff --git a/fs/proc/net.c b/fs/proc/net.c
deleted file mode 100644
index b4e18bc49..000000000
--- a/fs/proc/net.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * linux/fs/proc/net.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * gjh 3/'93 heim@peanuts.informatik.uni-tuebingen.de (Gerald J. Heim)
- * most of this file is stolen from base.c
- * it works, but you shouldn't use it as a guideline
- * for new proc-fs entries. once i'll make it better.
- * fvk 3/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen)
- * cleaned up the whole thing, moved "net" specific code to
- * the NET kernel layer (where it belonged in the first place).
- * Michael K. Johnson (johnsonm@stolaf.edu) 3/93
- * Added support from my previous inet.c. Cleaned things up
- * quite a bit, modularized the code.
- * fvk 4/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen)
- * Renamed "route_get_info()" to "rt_get_info()" for consistency.
- * Alan Cox (gw4pts@gw4pts.ampr.org) 4/94
- * Dusted off the code and added IPX. Fixed the 4K limit.
- * Erik Schoenfelder (schoenfr@ibr.cs.tu-bs.de)
- * /proc/net/snmp.
- * Alan Cox (gw4pts@gw4pts.ampr.org) 1/95
- * Added AppleTalk slots
- *
- * proc net directory handling functions
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-
-#include <asm/uaccess.h>
-
-#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
-
-static long proc_readnet(struct inode * inode, struct file * file,
- char * buf, unsigned long count)
-{
- char * page;
- int bytes=count;
- int copied=0;
- char *start;
- struct proc_dir_entry * dp;
-
- if (count < 0)
- return -EINVAL;
- dp = (struct proc_dir_entry *) inode->u.generic_ip;
- if (!(page = (char*) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
-
- while (bytes>0)
- {
- int length, thistime=bytes;
- if (bytes > PROC_BLOCK_SIZE)
- thistime=PROC_BLOCK_SIZE;
-
- length = dp->get_info(page, &start,
- file->f_pos,
- thistime,
- (file->f_flags & O_ACCMODE) == O_RDWR);
-
- /*
- * We have been given a non page aligned block of
- * the data we asked for + a bit. We have been given
- * the start pointer and we know the length..
- */
-
- if (length <= 0)
- break;
- /*
- * Copy the bytes
- */
- copy_to_user(buf+copied, start, length);
- file->f_pos += length; /* Move down the file */
- bytes -= length;
- copied += length;
- if (length<thistime)
- break; /* End of file */
- }
- free_page((unsigned long) page);
- return copied;
-}
-
-static struct file_operations proc_net_operations = {
- NULL, /* lseek - default */
- proc_readnet, /* read - bad */
- NULL, /* write - bad */
- NULL, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-/*
- * proc directories can do almost nothing..
- */
-struct inode_operations proc_net_inode_operations = {
- &proc_net_operations, /* default net file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
new file mode 100644
index 000000000..8ea9813a6
--- /dev/null
+++ b/fs/proc/proc_misc.c
@@ -0,0 +1,692 @@
+/*
+ * linux/fs/proc/proc_misc.c
+ *
+ * linux/fs/proc/array.c
+ * Copyright (C) 1992 by Linus Torvalds
+ * based on ideas by Darren Senn
+ *
+ * This used to be the part of array.c. See the rest of history and credits
+ * there. I took this into a separate file and switched the thing to generic
+ * proc_file_inode_operations, leaving in array.c only per-process stuff.
+ * Inumbers allocation made dynamic (via create_proc_entry()). AV, May 1999.
+ */
+
+#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/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 <linux/module.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+
+#define LOAD_INT(x) ((x) >> FSHIFT)
+#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
+/*
+ * Warning: stuff below (imported functions) assumes that its output will fit
+ * into one page. For some of those functions it may be wrong. Moreover, we
+ * have a way to deal with that gracefully. Right now I used straightforward
+ * wrappers, but this needs further analysis wrt potential overflows.
+ */
+extern int get_cpuinfo(char *);
+extern int get_hardware_list(char *);
+extern int get_stram_list(char *);
+#ifdef CONFIG_DEBUG_MALLOC
+extern int get_malloc(char * buffer);
+#endif
+#ifdef CONFIG_MODULES
+extern int get_module_list(char *);
+extern int get_ksyms_list(char *, char **, off_t, int);
+#endif
+extern int get_device_list(char *);
+extern int get_partition_list(char *);
+extern int get_filesystem_list(char *);
+extern int get_filesystem_info(char *);
+extern int get_exec_domain_list(char *);
+extern int get_irq_list(char *);
+extern int get_dma_list(char *);
+extern int get_rtc_status (char *);
+extern int get_locks_status (char *, char **, off_t, int);
+extern int get_swaparea_info (char *);
+#ifdef CONFIG_SGI_DS1286
+extern int get_ds1286_status(char *);
+#endif
+
+static int loadavg_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int a, b, c;
+ int len;
+
+ a = avenrun[0] + (FIXED_1/200);
+ b = avenrun[1] + (FIXED_1/200);
+ c = avenrun[2] + (FIXED_1/200);
+ len = sprintf(page,"%d.%02d %d.%02d %d.%02d %d/%d %d\n",
+ LOAD_INT(a), LOAD_FRAC(a),
+ LOAD_INT(b), LOAD_FRAC(b),
+ LOAD_INT(c), LOAD_FRAC(c),
+ nr_running, nr_threads, last_pid);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int uptime_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ unsigned long uptime;
+ unsigned long idle;
+ int len;
+
+ uptime = jiffies;
+ idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
+
+ /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
+ that would overflow about every five days at HZ == 100.
+ Therefore the identity a = (a / b) * b + a % b is used so that it is
+ calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100.
+ The part in front of the '+' always evaluates as 0 (mod 100). All divisions
+ in the above formulas are truncating. For HZ being a power of 10, the
+ calculations simplify to the version in the #else part (if the printf
+ format is adapted to the same number of digits as zeroes in HZ.
+ */
+#if HZ!=100
+ len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
+ uptime / HZ,
+ (((uptime % HZ) * 100) / HZ) % 100,
+ idle / HZ,
+ (((idle % HZ) * 100) / HZ) % 100);
+#else
+ len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
+ uptime / HZ,
+ uptime % HZ,
+ idle / HZ,
+ idle % HZ);
+#endif
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int meminfo_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct sysinfo i;
+ int len;
+
+/*
+ * display in kilobytes.
+ */
+#define K(x) ((x) << (PAGE_SHIFT - 10))
+#define B(x) ((x) << PAGE_SHIFT)
+ si_meminfo(&i);
+ si_swapinfo(&i);
+ len = sprintf(page, " total: used: free: shared: buffers: cached:\n"
+ "Mem: %8lu %8lu %8lu %8lu %8lu %8u\n"
+ "Swap: %8lu %8lu %8lu\n",
+ B(i.totalram), B(i.totalram-i.freeram), B(i.freeram),
+ B(i.sharedram), B(i.bufferram),
+ B(atomic_read(&page_cache_size)), B(i.totalswap),
+ B(i.totalswap-i.freeswap), B(i.freeswap));
+ /*
+ * Tagged format, for easy grepping and expansion.
+ * The above will go away eventually, once the tools
+ * have been updated.
+ */
+ len += sprintf(page+len,
+ "MemTotal: %8lu kB\n"
+ "MemFree: %8lu kB\n"
+ "MemShared: %8lu kB\n"
+ "Buffers: %8lu kB\n"
+ "Cached: %8u kB\n"
+ "HighTotal: %8lu kB\n"
+ "HighFree: %8lu kB\n"
+ "LowTotal: %8lu kB\n"
+ "LowFree: %8lu kB\n"
+ "SwapTotal: %8lu kB\n"
+ "SwapFree: %8lu kB\n",
+ K(i.totalram),
+ K(i.freeram),
+ K(i.sharedram),
+ K(i.bufferram),
+ K(atomic_read(&page_cache_size)),
+ K(i.totalhigh),
+ K(i.freehigh),
+ K(i.totalram-i.totalhigh),
+ K(i.freeram-i.freehigh),
+ K(i.totalswap),
+ K(i.freeswap));
+
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+#undef B
+#undef K
+}
+
+static int version_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ extern char *linux_banner;
+ int len;
+
+ strcpy(page, linux_banner);
+ len = strlen(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int cpuinfo_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_cpuinfo(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+#ifdef CONFIG_PROC_HARDWARE
+static int hardware_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_hardware_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#endif
+
+#ifdef CONFIG_STRAM_PROC
+static int stram_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_stram_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#endif
+
+#ifdef CONFIG_DEBUG_MALLOC
+static int malloc_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_malloc(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#endif
+
+#ifdef CONFIG_MODULES
+static int modules_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_module_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int ksyms_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_ksyms_list(page, start, off, count);
+ if (len < count) *eof = 1;
+ return len;
+}
+#endif
+
+static int kstat_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int i, len;
+ unsigned sum = 0;
+ extern unsigned long total_forks;
+ unsigned long jif = jiffies;
+
+ for (i = 0 ; i < NR_IRQS ; i++)
+ sum += kstat_irqs(i);
+
+#ifdef __SMP__
+ len = sprintf(page,
+ "cpu %u %u %u %lu\n",
+ kstat.cpu_user,
+ kstat.cpu_nice,
+ kstat.cpu_system,
+ jif*smp_num_cpus - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system));
+ for (i = 0 ; i < smp_num_cpus; i++)
+ len += sprintf(page + len, "cpu%d %u %u %u %lu\n",
+ i,
+ kstat.per_cpu_user[cpu_logical_map(i)],
+ kstat.per_cpu_nice[cpu_logical_map(i)],
+ kstat.per_cpu_system[cpu_logical_map(i)],
+ jif - ( kstat.per_cpu_user[cpu_logical_map(i)] \
+ + kstat.per_cpu_nice[cpu_logical_map(i)] \
+ + kstat.per_cpu_system[cpu_logical_map(i)]));
+ len += sprintf(page + len,
+ "disk %u %u %u %u\n"
+ "disk_rio %u %u %u %u\n"
+ "disk_wio %u %u %u %u\n"
+ "disk_rblk %u %u %u %u\n"
+ "disk_wblk %u %u %u %u\n"
+ "page %u %u\n"
+ "swap %u %u\n"
+ "intr %u",
+#else
+ len = sprintf(page,
+ "cpu %u %u %u %lu\n"
+ "disk %u %u %u %u\n"
+ "disk_rio %u %u %u %u\n"
+ "disk_wio %u %u %u %u\n"
+ "disk_rblk %u %u %u %u\n"
+ "disk_wblk %u %u %u %u\n"
+ "page %u %u\n"
+ "swap %u %u\n"
+ "intr %u",
+ kstat.cpu_user,
+ kstat.cpu_nice,
+ kstat.cpu_system,
+ jif*smp_num_cpus - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system),
+#endif
+ kstat.dk_drive[0], kstat.dk_drive[1],
+ kstat.dk_drive[2], kstat.dk_drive[3],
+ kstat.dk_drive_rio[0], kstat.dk_drive_rio[1],
+ kstat.dk_drive_rio[2], kstat.dk_drive_rio[3],
+ kstat.dk_drive_wio[0], kstat.dk_drive_wio[1],
+ kstat.dk_drive_wio[2], kstat.dk_drive_wio[3],
+ kstat.dk_drive_rblk[0], kstat.dk_drive_rblk[1],
+ kstat.dk_drive_rblk[2], kstat.dk_drive_rblk[3],
+ kstat.dk_drive_wblk[0], kstat.dk_drive_wblk[1],
+ kstat.dk_drive_wblk[2], kstat.dk_drive_wblk[3],
+ kstat.pgpgin,
+ kstat.pgpgout,
+ kstat.pswpin,
+ kstat.pswpout,
+ sum);
+ for (i = 0 ; i < NR_IRQS ; i++)
+ len += sprintf(page + len, " %u", kstat_irqs(i));
+ len += sprintf(page + len,
+ "\nctxt %u\n"
+ "btime %lu\n"
+ "processes %lu\n",
+ kstat.context_swtch,
+ xtime.tv_sec - jif / HZ,
+ total_forks);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int devices_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_device_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int partitions_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_partition_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int interrupts_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_irq_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int filesystems_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_filesystem_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int dma_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_dma_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int ioports_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_ioport_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int cmdline_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ extern char saved_command_line[];
+ int len;
+
+ len = sprintf(page, "%s\n", saved_command_line);
+ len = strlen(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+#ifdef CONFIG_RTC
+static int rtc_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_rtc_status(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#endif
+
+#ifdef CONFIG_SGI_DS1286
+static int ds1286_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_ds1286_status(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#endif
+
+static int locks_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_locks_status(page, start, off, count);
+ if (len < count) *eof = 1;
+ return len;
+}
+
+static int mounts_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_filesystem_info(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int execdomains_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_exec_domain_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int swaps_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_swaparea_info(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int slabinfo_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_slabinfo(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int memory_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_mem_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+/*
+ * This function accesses profiling information. The returned data is
+ * binary: the sampling step and the actual contents of the profile
+ * buffer. Use of the program readprofile is recommended in order to
+ * get meaningful info out of these data.
+ */
+static ssize_t read_profile(struct file *file, char *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned long p = *ppos;
+ ssize_t read;
+ char * pnt;
+ unsigned int sample_step = 1 << prof_shift;
+
+ if (p >= (prof_len+1)*sizeof(unsigned int))
+ return 0;
+ if (count > (prof_len+1)*sizeof(unsigned int) - p)
+ count = (prof_len+1)*sizeof(unsigned int) - p;
+ read = 0;
+
+ while (p < sizeof(unsigned int) && count > 0) {
+ put_user(*((char *)(&sample_step)+p),buf);
+ buf++; p++; count--; read++;
+ }
+ pnt = (char *)prof_buffer + p - sizeof(unsigned int);
+ copy_to_user(buf,(void *)pnt,count);
+ read += count;
+ *ppos += read;
+ return read;
+}
+
+/*
+ * Writing to /proc/profile resets the counters
+ *
+ * Writing a 'profiling multiplier' value into it also re-sets the profiling
+ * interrupt frequency, on architectures that support this.
+ */
+static ssize_t write_profile(struct file * file, const char * buf,
+ size_t count, loff_t *ppos)
+{
+#ifdef __SMP__
+ extern int setup_profiling_timer (unsigned int multiplier);
+
+ if (count==sizeof(int)) {
+ unsigned int multiplier;
+
+ if (copy_from_user(&multiplier, buf, sizeof(int)))
+ return -EFAULT;
+
+ if (setup_profiling_timer(multiplier))
+ return -EINVAL;
+ }
+#endif
+
+ memset(prof_buffer, 0, prof_len * sizeof(*prof_buffer));
+ return count;
+}
+
+static struct file_operations proc_profile_operations = {
+ NULL, /* lseek */
+ read_profile,
+ write_profile,
+};
+
+static struct inode_operations proc_profile_inode_operations = {
+ &proc_profile_operations,
+};
+
+static struct proc_dir_entry proc_root_kmsg = {
+ 0, 4, "kmsg",
+ S_IFREG | S_IRUSR, 1, 0, 0,
+ 0, &proc_kmsg_inode_operations
+};
+struct proc_dir_entry proc_root_kcore = {
+ 0, 5, "kcore",
+ S_IFREG | S_IRUSR, 1, 0, 0,
+ 0, &proc_kcore_inode_operations
+};
+static struct proc_dir_entry proc_root_profile = {
+ 0, 7, "profile",
+ S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
+ 0, &proc_profile_inode_operations
+};
+
+void proc_misc_init(void)
+{
+ static struct {
+ char *name;
+ int (*read_proc)(char*,char**,off_t,int,int*,void*);
+ } *p, simple_ones[] = {
+ {"loadavg", loadavg_read_proc},
+ {"uptime", uptime_read_proc},
+ {"meminfo", meminfo_read_proc},
+ {"version", version_read_proc},
+ {"cpuinfo", cpuinfo_read_proc},
+#ifdef CONFIG_PROC_HARDWARE
+ {"hardware", hardware_read_proc},
+#endif
+#ifdef CONFIG_STRAM_PROC
+ {"stram", stram_read_proc},
+#endif
+#ifdef CONFIG_DEBUG_MALLOC
+ {"malloc", malloc_read_proc},
+#endif
+#ifdef CONFIG_MODULES
+ {"modules", modules_read_proc},
+ {"ksyms", ksyms_read_proc},
+#endif
+ {"stat", kstat_read_proc},
+ {"devices", devices_read_proc},
+ {"partitions", partitions_read_proc},
+ {"interrupts", interrupts_read_proc},
+ {"filesystems", filesystems_read_proc},
+ {"dma", dma_read_proc},
+ {"ioports", ioports_read_proc},
+ {"cmdline", cmdline_read_proc},
+#ifdef CONFIG_RTC
+ {"rtc", rtc_read_proc},
+#endif
+#ifdef CONFIG_SGI_DS1286
+ {"rtc", ds1286_read_proc},
+#endif
+ {"locks", locks_read_proc},
+ {"mounts", mounts_read_proc},
+ {"swaps", swaps_read_proc},
+ {"slabinfo", slabinfo_read_proc},
+ {"iomem", memory_read_proc},
+ {"execdomains", execdomains_read_proc},
+ {NULL,NULL}
+ };
+ for(p=simple_ones;p->name;p++)
+ create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL);
+
+ /* And now for trickier ones */
+ proc_register(&proc_root, &proc_root_kmsg);
+ proc_register(&proc_root, &proc_root_kcore);
+ proc_root_kcore.size = (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE;
+ if (prof_shift) {
+ proc_register(&proc_root, &proc_root_profile);
+ proc_root_profile.size = (1+prof_len) * sizeof(unsigned int);
+ }
+}
diff --git a/fs/proc/procfs_syms.c b/fs/proc/procfs_syms.c
index c6d0032c5..fa2ee362e 100644
--- a/fs/proc/procfs_syms.c
+++ b/fs/proc/procfs_syms.c
@@ -3,15 +3,7 @@
#include <linux/fs.h>
#include <linux/proc_fs.h>
-/*
- * This is all required so that if we load all of scsi as a module,
- * that the scsi code will be able to talk to the /proc/scsi handling
- * in the procfs.
- */
-extern int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
- off_t offset, int length, int inout);
-extern struct inode_operations proc_scsi_inode_operations;
-extern struct proc_dir_entry proc_sys_root;
+extern struct proc_dir_entry *proc_sys_root;
#ifdef CONFIG_SYSCTL
EXPORT_SYMBOL(proc_sys_root);
@@ -24,18 +16,9 @@ EXPORT_SYMBOL(proc_root);
EXPORT_SYMBOL(proc_root_fs);
EXPORT_SYMBOL(proc_get_inode);
EXPORT_SYMBOL(proc_dir_inode_operations);
-EXPORT_SYMBOL(proc_net_inode_operations);
EXPORT_SYMBOL(proc_net);
EXPORT_SYMBOL(proc_bus);
-/*
- * This is required so that if we load scsi later, that the
- * scsi code can attach to /proc/scsi in the correct manner.
- */
-EXPORT_SYMBOL(proc_scsi);
-EXPORT_SYMBOL(proc_scsi_inode_operations);
-EXPORT_SYMBOL(dispatch_scsi_info_ptr);
-
#if defined(CONFIG_SUN_OPENPROMFS_MODULE)
EXPORT_SYMBOL(proc_openprom_register);
EXPORT_SYMBOL(proc_openprom_deregister);
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 84478312c..b87b0fb4f 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -22,11 +22,6 @@
#include <linux/zorro.h>
#endif
-/*
- * Offset of the first process in the /proc root directory..
- */
-#define FIRST_PROCESS_ENTRY 256
-
static int proc_root_readdir(struct file *, void *, filldir_t);
static struct dentry *proc_root_lookup(struct inode *,struct dentry *);
static int proc_unlink(struct inode *, struct dentry *);
@@ -37,22 +32,12 @@ static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
* These are the generic /proc directory operations. They
* use the in-memory "struct proc_dir_entry" tree to parse
* the /proc directory.
- *
- * NOTE! The /proc/scsi directory currently does not correctly
- * build up the proc_dir_entry tree, and will show up empty.
*/
static struct file_operations proc_dir_operations = {
NULL, /* lseek - default */
NULL, /* read - bad */
NULL, /* write - bad */
proc_readdir, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
};
/*
@@ -62,23 +47,6 @@ struct inode_operations proc_dir_inode_operations = {
&proc_dir_operations, /* default net directory file-ops */
NULL, /* create */
proc_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
};
/*
@@ -90,21 +58,6 @@ struct inode_operations proc_dyna_dir_inode_operations = {
proc_lookup, /* lookup */
NULL, /* link */
proc_unlink, /* unlink(struct inode *, struct dentry *) */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
};
/*
@@ -117,13 +70,6 @@ static struct file_operations proc_root_operations = {
NULL, /* read - bad */
NULL, /* write - bad */
proc_root_readdir, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* no fsync */
};
/*
@@ -133,23 +79,6 @@ static struct inode_operations proc_root_inode_operations = {
&proc_root_operations, /* default base directory file-ops */
NULL, /* create */
proc_root_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
};
/*
@@ -164,27 +93,14 @@ struct proc_dir_entry proc_root = {
&proc_root, NULL
};
-struct proc_dir_entry *proc_net, *proc_scsi, *proc_bus, *proc_sysvipc;
+struct proc_dir_entry *proc_net, *proc_bus, *proc_root_fs, *proc_root_driver;
#ifdef CONFIG_MCA
-struct proc_dir_entry proc_mca = {
- PROC_MCA, 3, "mca",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_dir_inode_operations,
- NULL, NULL,
- NULL, &proc_root, NULL
-};
+struct proc_dir_entry *proc_mca;
#endif
#ifdef CONFIG_SYSCTL
-struct proc_dir_entry proc_sys_root = {
- PROC_SYS, 3, "sys", /* inode, name */
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, /* mode, nlink, uid, gid */
- 0, &proc_dir_inode_operations, /* size, ops */
- NULL, NULL, /* get_info, fill_inode */
- NULL, /* next */
- NULL, NULL /* parent, subdir */
-};
+struct proc_dir_entry *proc_sys_root;
#endif
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
@@ -280,36 +196,12 @@ static struct file_operations proc_openprom_operations = {
NULL, /* read - bad */
NULL, /* write - bad */
OPENPROM_DEFREADDIR, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
};
struct inode_operations proc_openprom_inode_operations = {
&proc_openprom_operations,/* default net directory file-ops */
NULL, /* create */
OPENPROM_DEFLOOKUP, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
};
struct proc_dir_entry proc_openprom = {
@@ -333,6 +225,73 @@ static int make_inode_number(void)
return PROC_DYNAMIC_FIRST + i;
}
+int proc_readlink(struct dentry * dentry, char * buffer, int buflen)
+{
+ struct inode *inode = dentry->d_inode;
+ struct proc_dir_entry * de;
+ char *page;
+ int len = 0;
+
+ de = (struct proc_dir_entry *) inode->u.generic_ip;
+ if (!de)
+ return -ENOENT;
+ if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+
+ if (de->readlink_proc)
+ len = de->readlink_proc(de, page);
+
+ if (len > buflen)
+ len = buflen;
+
+ copy_to_user(buffer, page, len);
+ free_page((unsigned long) page);
+ return len;
+}
+
+struct dentry * proc_follow_link(struct dentry * dentry, struct dentry *base, unsigned int follow)
+{
+ struct inode *inode = dentry->d_inode;
+ struct proc_dir_entry * de;
+ char *page;
+ struct dentry *d;
+ int len = 0;
+
+ de = (struct proc_dir_entry *) inode->u.generic_ip;
+ if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+ return NULL;
+
+ if (de->readlink_proc)
+ len = de->readlink_proc(de, page);
+
+ d = lookup_dentry(page, base, follow);
+ free_page((unsigned long) page);
+ return d;
+}
+
+static struct inode_operations proc_link_inode_operations = {
+ NULL, /* no file-ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ proc_readlink, /* readlink */
+ proc_follow_link, /* follow_link */
+ NULL, /* get_block */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* flushpage */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
+};
+
int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
{
int i;
@@ -445,50 +404,6 @@ static struct dentry * proc_self_follow_link(struct dentry *dentry,
return lookup_dentry(tmp, base, follow);
}
-int proc_readlink(struct dentry * dentry, char * buffer, int buflen)
-{
- struct inode *inode = dentry->d_inode;
- struct proc_dir_entry * de;
- char *page;
- int len = 0;
-
- de = (struct proc_dir_entry *) inode->u.generic_ip;
- if (!de)
- return -ENOENT;
- if (!(page = (char*) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
-
- if (de->readlink_proc)
- len = de->readlink_proc(de, page);
-
- if (len > buflen)
- len = buflen;
-
- copy_to_user(buffer, page, len);
- free_page((unsigned long) page);
- return len;
-}
-
-struct dentry * proc_follow_link(struct dentry * dentry, struct dentry *base, unsigned int follow)
-{
- struct inode *inode = dentry->d_inode;
- struct proc_dir_entry * de;
- char *page;
- struct dentry *d;
- int len = 0;
-
- de = (struct proc_dir_entry *) inode->u.generic_ip;
- if (!(page = (char*) __get_free_page(GFP_KERNEL)))
- return NULL;
-
- if (de->readlink_proc)
- len = de->readlink_proc(de, page);
-
- d = lookup_dentry(page, base, follow);
- free_page((unsigned long) page);
- return d;
-}
-
static struct inode_operations proc_self_inode_operations = {
NULL, /* no file-ops */
NULL, /* create */
@@ -512,286 +427,41 @@ static struct inode_operations proc_self_inode_operations = {
NULL /* revalidate */
};
-static struct inode_operations proc_link_inode_operations = {
- NULL, /* no file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- proc_readlink, /* readlink */
- proc_follow_link, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-static struct proc_dir_entry proc_root_loadavg = {
- PROC_LOADAVG, 7, "loadavg",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_uptime = {
- PROC_UPTIME, 6, "uptime",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_meminfo = {
- PROC_MEMINFO, 7, "meminfo",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_kmsg = {
- PROC_KMSG, 4, "kmsg",
- S_IFREG | S_IRUSR, 1, 0, 0,
- 0, &proc_kmsg_inode_operations
-};
-static struct proc_dir_entry proc_root_version = {
- PROC_VERSION, 7, "version",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_cpuinfo = {
- PROC_CPUINFO, 7, "cpuinfo",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#if defined (CONFIG_PROC_HARDWARE)
-static struct proc_dir_entry proc_root_hardware = {
- PROC_HARDWARE, 8, "hardware",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
-#ifdef CONFIG_STRAM_PROC
-static struct proc_dir_entry proc_root_stram = {
- PROC_STRAM, 5, "stram",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
static struct proc_dir_entry proc_root_self = {
- PROC_SELF, 4, "self",
+ 0, 4, "self",
S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0,
64, &proc_self_inode_operations,
};
-#ifdef CONFIG_DEBUG_MALLOC
-static struct proc_dir_entry proc_root_malloc = {
- PROC_MALLOC, 6, "malloc",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
-static struct proc_dir_entry proc_root_kcore = {
- PROC_KCORE, 5, "kcore",
- S_IFREG | S_IRUSR, 1, 0, 0,
- 0, &proc_kcore_inode_operations
-};
-#ifdef CONFIG_MODULES
-static struct proc_dir_entry proc_root_modules = {
- PROC_MODULES, 7, "modules",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_ksyms = {
- PROC_KSYMS, 5, "ksyms",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
-static struct proc_dir_entry proc_root_stat = {
- PROC_STAT, 4, "stat",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_devices = {
- PROC_DEVICES, 7, "devices",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_partitions = {
- PROC_PARTITIONS, 10, "partitions",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_interrupts = {
- PROC_INTERRUPTS, 10,"interrupts",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_filesystems = {
- PROC_FILESYSTEMS, 11,"filesystems",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-struct proc_dir_entry proc_root_fs = {
- PROC_FS, 2, "fs",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_dir_inode_operations,
- NULL, NULL,
- NULL,
- NULL, NULL
-};
-struct proc_dir_entry proc_root_driver = {
- PROC_DRIVER, 6, "driver",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_dir_inode_operations,
- NULL, NULL,
- NULL,
- NULL, NULL
-};
-static struct proc_dir_entry proc_root_dma = {
- PROC_DMA, 3, "dma",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_ioports = {
- PROC_IOPORTS, 7, "ioports",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_iomem = {
- PROC_MEMORY, 5, "iomem",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_cmdline = {
- PROC_CMDLINE, 7, "cmdline",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#ifdef CONFIG_RTC
-static struct proc_dir_entry proc_root_rtc = {
- PROC_RTC, 3, "rtc",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
-#ifdef CONFIG_SGI_DS1286
-static struct proc_dir_entry proc_root_ds1286 = {
- PROC_RTC, 3, "rtc",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
-static struct proc_dir_entry proc_root_locks = {
- PROC_LOCKS, 5, "locks",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_mounts = {
- PROC_MTAB, 6, "mounts",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_swaps = {
- PROC_SWAP, 5, "swaps",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_profile = {
- PROC_PROFILE, 7, "profile",
- S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
- 0, &proc_profile_inode_operations
-};
-static struct proc_dir_entry proc_root_slab = {
- PROC_SLABINFO, 8, "slabinfo",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
#ifdef __powerpc__
static struct proc_dir_entry proc_root_ppc_htab = {
- PROC_PPC_HTAB, 8, "ppc_htab",
+ 0, 8, "ppc_htab",
S_IFREG | S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, 1, 0, 0,
0, &proc_ppc_htab_inode_operations,
- NULL, NULL, /* get_info, fill_inode */
- NULL, /* next */
- NULL, NULL /* parent, subdir */
};
#endif
void __init proc_root_init(void)
{
- proc_base_init();
- proc_register(&proc_root, &proc_root_loadavg);
- proc_register(&proc_root, &proc_root_uptime);
- proc_register(&proc_root, &proc_root_meminfo);
- proc_register(&proc_root, &proc_root_kmsg);
- proc_register(&proc_root, &proc_root_version);
- proc_register(&proc_root, &proc_root_cpuinfo);
+ proc_misc_init();
proc_register(&proc_root, &proc_root_self);
proc_net = create_proc_entry("net", S_IFDIR, 0);
- proc_scsi = create_proc_entry("scsi", S_IFDIR, 0);
#ifdef CONFIG_SYSVIPC
- proc_sysvipc = create_proc_entry("sysvipc", S_IFDIR, 0);
+ create_proc_entry("sysvipc", S_IFDIR, 0);
#endif
#ifdef CONFIG_SYSCTL
- proc_register(&proc_root, &proc_sys_root);
+ proc_sys_root = create_proc_entry("sys", S_IFDIR, 0);
#endif
#ifdef CONFIG_MCA
- proc_register(&proc_root, &proc_mca);
-#endif
-
-#ifdef CONFIG_DEBUG_MALLOC
- proc_register(&proc_root, &proc_root_malloc);
-#endif
- proc_register(&proc_root, &proc_root_kcore);
- proc_root_kcore.size = (MAP_NR(high_memory) << PAGE_SHIFT) + PAGE_SIZE;
-
-#ifdef CONFIG_MODULES
- proc_register(&proc_root, &proc_root_modules);
- proc_register(&proc_root, &proc_root_ksyms);
-#endif
- proc_register(&proc_root, &proc_root_stat);
- proc_register(&proc_root, &proc_root_devices);
- proc_register(&proc_root, &proc_root_driver);
- proc_register(&proc_root, &proc_root_partitions);
- proc_register(&proc_root, &proc_root_interrupts);
- proc_register(&proc_root, &proc_root_filesystems);
- proc_register(&proc_root, &proc_root_fs);
- proc_register(&proc_root, &proc_root_dma);
- proc_register(&proc_root, &proc_root_ioports);
- proc_register(&proc_root, &proc_root_iomem);
- proc_register(&proc_root, &proc_root_cmdline);
-#ifdef CONFIG_RTC
- proc_register(&proc_root, &proc_root_rtc);
-#endif
-#ifdef CONFIG_SGI_DS1286
- proc_register(&proc_root, &proc_root_ds1286);
+ proc_mca = create_proc_entry("mca", S_IFDIR, 0);
#endif
- proc_register(&proc_root, &proc_root_locks);
-
- proc_register(&proc_root, &proc_root_mounts);
- proc_register(&proc_root, &proc_root_swaps);
-
+ proc_root_fs = create_proc_entry("fs", S_IFDIR, 0);
+ proc_root_driver = create_proc_entry("driver", S_IFDIR, 0);
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
#ifdef CONFIG_SUN_OPENPROMFS
openpromfs_init ();
#endif
proc_register(&proc_root, &proc_openprom);
#endif
-#ifdef CONFIG_PROC_HARDWARE
- proc_register(&proc_root, &proc_root_hardware);
-#endif
-#ifdef CONFIG_STRAM_PROC
- proc_register(&proc_root, &proc_root_stram);
-#endif
- proc_register(&proc_root, &proc_root_slab);
-
- if (prof_shift) {
- proc_register(&proc_root, &proc_root_profile);
- proc_root_profile.size = (1+prof_len) * sizeof(unsigned int);
- }
-
proc_tty_init();
#ifdef __powerpc__
proc_register(&proc_root, &proc_root_ppc_htab);
@@ -799,7 +469,6 @@ void __init proc_root_init(void)
#ifdef CONFIG_PROC_DEVICETREE
proc_device_tree_init();
#endif
-
proc_bus = create_proc_entry("bus", S_IFDIR, 0);
}
@@ -843,7 +512,7 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry)
if (de->namelen != dentry->d_name.len)
continue;
if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
- int ino = de->low_ino | (dir->i_ino & ~(0xffff));
+ int ino = de->low_ino;
error = -EINVAL;
inode = proc_get_inode(dir->i_sb, ino, de);
break;
@@ -861,11 +530,7 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry)
static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry)
{
- unsigned int pid, c;
struct task_struct *p;
- const char *name;
- struct inode *inode;
- int len;
if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */
extern unsigned long total_forks;
@@ -896,40 +561,7 @@ static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentr
if (!proc_lookup(dir, dentry))
return NULL;
- pid = 0;
- name = dentry->d_name.name;
- len = dentry->d_name.len;
- while (len-- > 0) {
- c = *name - '0';
- name++;
- if (c > 9) {
- pid = 0;
- break;
- }
- pid *= 10;
- pid += c;
- if (!pid)
- break;
- if (pid & 0xffff0000) {
- pid = 0;
- break;
- }
- }
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- read_unlock(&tasklist_lock);
- inode = NULL;
- if (pid && p) {
- unsigned long ino = (pid << 16) + PROC_PID_INO;
- inode = proc_get_inode(dir->i_sb, ino, &proc_pid);
- if (!inode)
- return ERR_PTR(-EINVAL);
- inode->i_flags|=S_IMMUTABLE;
- }
-
- dentry->d_op = &proc_dentry_operations;
- d_add(dentry, inode);
- return NULL;
+ return proc_pid_lookup(dir, dentry);
}
/*
@@ -968,7 +600,6 @@ int proc_readdir(struct file * filp,
filp->f_pos++;
/* fall through */
default:
- ino &= ~0xffff;
de = de->subdir;
i -= 2;
for (;;) {
@@ -981,7 +612,7 @@ int proc_readdir(struct file * filp,
}
do {
- if (filldir(dirent, de->name, de->namelen, filp->f_pos, ino | de->low_ino) < 0)
+ if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino) < 0)
return 0;
filp->f_pos++;
de = de->next;
@@ -990,69 +621,19 @@ int proc_readdir(struct file * filp,
return 1;
}
-#define PROC_NUMBUF 10
-#define PROC_MAXPIDS 20
-
-/*
- * Get a few pid's to return for filldir - we need to hold the
- * tasklist lock while doing this, and we must release it before
- * we actually do the filldir itself, so we use a temp buffer..
- */
-static int get_pid_list(int index, unsigned int *pids)
-{
- struct task_struct *p;
- int nr_pids = 0;
-
- index -= FIRST_PROCESS_ENTRY;
- read_lock(&tasklist_lock);
- for_each_task(p) {
- int pid = p->pid;
- if (!pid)
- continue;
- if (--index >= 0)
- continue;
- pids[nr_pids] = pid;
- nr_pids++;
- if (nr_pids >= PROC_MAXPIDS)
- break;
- }
- read_unlock(&tasklist_lock);
- return nr_pids;
-}
-
static int proc_root_readdir(struct file * filp,
void * dirent, filldir_t filldir)
{
- unsigned int pid_array[PROC_MAXPIDS];
- char buf[PROC_NUMBUF];
unsigned int nr = filp->f_pos;
- unsigned int nr_pids, i;
if (nr < FIRST_PROCESS_ENTRY) {
int error = proc_readdir(filp, dirent, filldir);
if (error <= 0)
return error;
- filp->f_pos = nr = FIRST_PROCESS_ENTRY;
+ filp->f_pos = FIRST_PROCESS_ENTRY;
}
- nr_pids = get_pid_list(nr, pid_array);
-
- for (i = 0; i < nr_pids; i++) {
- int pid = pid_array[i];
- ino_t ino = (pid << 16) + PROC_PID_INO;
- unsigned long j = PROC_NUMBUF;
-
- do {
- j--;
- buf[j] = '0' + (pid % 10);
- pid /= 10;
- } while (pid);
-
- if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino) < 0)
- break;
- filp->f_pos++;
- }
- return 0;
+ return proc_pid_readdir(filp, dirent, filldir);
}
static int proc_unlink(struct inode *dir, struct dentry *dentry)
diff --git a/fs/proc/scsi.c b/fs/proc/scsi.c
deleted file mode 100644
index 679fa383f..000000000
--- a/fs/proc/scsi.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * linux/fs/proc/scsi.c
- * (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
- *
- * The original version was derived from linux/fs/proc/net.c,
- * which is Copyright (C) 1991, 1992 Linus Torvalds.
- * Much has been rewritten, but some of the code still remains.
- *
- * /proc/scsi directory handling functions
- *
- * last change: 95/07/04
- *
- * Initial version: March '95
- * 95/05/15 Added subdirectories for each driver and show every
- * registered HBA as a single file.
- * 95/05/30 Added rudimentary write support for parameter passing
- * 95/07/04 Fixed bugs in directory handling
- * 95/09/13 Update to support the new proc-dir tree
- *
- * TODO: Improve support to write to the driver files
- * Add some more comments
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-
-#include <asm/uaccess.h>
-
-/* forward references */
-static ssize_t proc_readscsi(struct file * file, char * buf,
- size_t count, loff_t *ppos);
-static ssize_t proc_writescsi(struct file * file, const char * buf,
- size_t count, loff_t *ppos);
-static long long proc_scsilseek(struct file *, long long, int);
-
-extern void build_proc_dir_hba_entries(uint);
-
-/* the *_get_info() functions are in the respective scsi driver code */
-int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
- off_t offset, int length, int inout) = 0;
-
-static struct file_operations proc_scsi_operations = {
- proc_scsilseek, /* lseek */
- proc_readscsi, /* read */
- proc_writescsi, /* write */
- proc_readdir, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-/*
- * proc directories can do almost nothing..
- */
-struct inode_operations proc_scsi_inode_operations = {
-&proc_scsi_operations, /* default scsi directory file-ops */
- NULL, /* create */
- proc_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-int get_not_present_info(char *buffer, char **start, off_t offset, int length)
-{
- int len, pos, begin;
-
- begin = 0;
- pos = len = sprintf(buffer,
- "No low-level scsi modules are currently present\n");
- if(pos < offset) {
- len = 0;
- begin = pos;
- }
-
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin);
- if(len > length)
- len = length;
-
- return(len);
-}
-
-#define PROC_BLOCK_SIZE (3*1024) /* 4K page size, but our output routines
- * use some slack for overruns
- */
-
-static ssize_t proc_readscsi(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- struct inode * inode = file->f_dentry->d_inode;
- ssize_t length;
- ssize_t bytes = count;
- ssize_t copied = 0;
- ssize_t thistime;
- char * page;
- char * start;
-
- if (!(page = (char *) __get_free_page(GFP_KERNEL)))
- return(-ENOMEM);
-
- while (bytes > 0) {
- thistime = bytes;
- if(bytes > PROC_BLOCK_SIZE)
- thistime = PROC_BLOCK_SIZE;
-
- if(dispatch_scsi_info_ptr)
- length = dispatch_scsi_info_ptr(inode->i_ino, page, &start,
- *ppos, thistime, 0);
- else
- length = get_not_present_info(page, &start, *ppos, thistime);
- if(length < 0) {
- free_page((ulong) page);
- return(length);
- }
-
- /*
- * We have been given a non page aligned block of
- * the data we asked for + a bit. We have been given
- * the start pointer and we know the length..
- */
- if (length <= 0)
- break;
- /*
- * Copy the bytes
- */
- copy_to_user(buf + copied, start, length);
- *ppos += length; /* Move down the file */
- bytes -= length;
- copied += length;
-
- if(length < thistime)
- break; /* End of file */
-
- }
-
- free_page((ulong) page);
- return(copied);
-}
-
-
-static ssize_t proc_writescsi(struct file * file, const char * buf,
- size_t count, loff_t *ppos)
-{
- struct inode * inode = file->f_dentry->d_inode;
- ssize_t ret = 0;
- char * page;
-
- if(count > PROC_BLOCK_SIZE) {
- return(-EOVERFLOW);
- }
-
- if(dispatch_scsi_info_ptr != NULL) {
- if (!(page = (char *) __get_free_page(GFP_KERNEL)))
- return(-ENOMEM);
- copy_from_user(page, buf, count);
- ret = dispatch_scsi_info_ptr(inode->i_ino, page, 0, 0, count, 1);
- } else
- return(-ENOPKG); /* Nothing here */
-
- free_page((ulong) page);
- return(ret);
-}
-
-
-static long long proc_scsilseek(struct file * file, long long offset, int orig)
-{
- switch (orig) {
- case 0:
- file->f_pos = offset;
- return(file->f_pos);
- case 1:
- file->f_pos += offset;
- return(file->f_pos);
- case 2:
- return(-EINVAL);
- default:
- return(-EINVAL);
- }
-}
-
-/*
- * Overrides for Emacs so that we almost follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff --git a/fs/proc/sysvipc.c b/fs/proc/sysvipc.c
deleted file mode 100644
index 7fff0ed03..000000000
--- a/fs/proc/sysvipc.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * linux/fs/proc/sysvipc.c
- *
- * Copyright (c) 1999 Dragos Acostachioaie
- *
- * This code is derived from linux/fs/proc/generic.c,
- * which is Copyright (C) 1991, 1992 Linus Torvalds.
- *
- * /proc/sysvipc directory handling functions
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-
-#include <asm/uaccess.h>
-
-#ifndef MIN
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
-/* 4K page size but our output routines use some slack for overruns */
-#define PROC_BLOCK_SIZE (3*1024)
-
-static ssize_t
-proc_sysvipc_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
-{
- struct inode * inode = file->f_dentry->d_inode;
- char *page;
- ssize_t retval=0;
- int eof=0;
- ssize_t n, count;
- char *start;
- struct proc_dir_entry * dp;
-
- dp = (struct proc_dir_entry *) inode->u.generic_ip;
- if (!(page = (char*) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
-
- while ((nbytes > 0) && !eof)
- {
- count = MIN(PROC_BLOCK_SIZE, nbytes);
-
- start = NULL;
- if (dp->get_info) {
- /*
- * Handle backwards compatibility with the old net
- * routines.
- *
- * XXX What gives with the file->f_flags & O_ACCMODE
- * test? Seems stupid to me....
- */
- n = dp->get_info(page, &start, *ppos, count,
- (file->f_flags & O_ACCMODE) == O_RDWR);
- if (n < count)
- eof = 1;
- } else if (dp->read_proc) {
- n = dp->read_proc(page, &start, *ppos,
- count, &eof, dp->data);
- } else
- break;
-
- if (!start) {
- /*
- * For proc files that are less than 4k
- */
- start = page + *ppos;
- n -= *ppos;
- if (n <= 0)
- break;
- if (n > count)
- n = count;
- }
- if (n == 0)
- break; /* End of file */
- if (n < 0) {
- if (retval == 0)
- retval = n;
- break;
- }
-
- /* This is a hack to allow mangling of file pos independent
- * of actual bytes read. Simply place the data at page,
- * return the bytes, and set `start' to the desired offset
- * as an unsigned int. - Paul.Russell@rustcorp.com.au
- */
- n -= copy_to_user(buf, start < page ? page : start, n);
- if (n == 0) {
- if (retval == 0)
- retval = -EFAULT;
- break;
- }
-
- *ppos += start < page ? (long)start : n; /* Move down the file */
- nbytes -= n;
- buf += n;
- retval += n;
- }
- free_page((unsigned long) page);
- return retval;
-}
-
-static struct file_operations proc_sysvipc_operations = {
- NULL, /* lseek */
- proc_sysvipc_read, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-/*
- * proc directories can do almost nothing..
- */
-struct inode_operations proc_sysvipc_inode_operations = {
- &proc_sysvipc_operations, /* default net file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};