diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
commit | 33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch) | |
tree | 2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /fs/proc | |
parent | 216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff) |
Merge with Linux 2.3.32.
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/Makefile | 2 | ||||
-rw-r--r-- | fs/proc/array.c | 1 | ||||
-rw-r--r-- | fs/proc/base.c | 21 | ||||
-rw-r--r-- | fs/proc/generic.c | 387 | ||||
-rw-r--r-- | fs/proc/inode-alloc.txt | 1 | ||||
-rw-r--r-- | fs/proc/inode.c | 87 | ||||
-rw-r--r-- | fs/proc/kcore.c | 74 | ||||
-rw-r--r-- | fs/proc/kmsg.c | 19 | ||||
-rw-r--r-- | fs/proc/omirr.c | 19 | ||||
-rw-r--r-- | fs/proc/openprom-dev.c | 46 | ||||
-rw-r--r-- | fs/proc/openpromfs.c | 208 | ||||
-rw-r--r-- | fs/proc/proc_devtree.c | 97 | ||||
-rw-r--r-- | fs/proc/proc_misc.c | 18 | ||||
-rw-r--r-- | fs/proc/proc_tty.c | 20 | ||||
-rw-r--r-- | fs/proc/procfs_syms.c | 12 | ||||
-rw-r--r-- | fs/proc/root.c | 563 |
16 files changed, 652 insertions, 923 deletions
diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 8ff6cd522..e8bb4774f 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -18,9 +18,11 @@ M_OBJS := ifeq ($(CONFIG_SUN_OPENPROMFS),y) O_OBJS += openpromfs.o +OX_OBJS := openprom-dev.o else ifeq ($(CONFIG_SUN_OPENPROMFS),m) M_OBJS += openpromfs.o + OX_OBJS := openprom-dev.o endif endif diff --git a/fs/proc/array.c b/fs/proc/array.c index eebb1f470..4ae097ca2 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -62,7 +62,6 @@ #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> diff --git a/fs/proc/base.c b/fs/proc/base.c index 866bb50d4..eac10cbd4 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -104,9 +104,12 @@ 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); + if (mm) { + int len = mm->env_end - mm->env_start; + if (len > PAGE_SIZE) + len = PAGE_SIZE; + res = access_process_vm(task, mm->env_start, buffer, len, 0); + } return res; } @@ -116,9 +119,12 @@ 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); + if (mm) { + int len = mm->arg_end - mm->arg_start; + if (len > PAGE_SIZE) + len = PAGE_SIZE; + res = access_process_vm(task, mm->arg_start, buffer, len, 0); + } return res; } @@ -363,10 +369,8 @@ static struct inode_operations proc_mem_inode_operations = { NULL, /* get_block */ NULL, /* readpage */ NULL, /* writepage */ - NULL, /* flushpage */ NULL, /* truncate */ proc_permission, /* permission */ - NULL, /* smap */ NULL /* revalidate */ }; @@ -788,7 +792,6 @@ static struct inode_operations proc_fd_inode_operations = { NULL, /* get_block */ NULL, /* readpage */ NULL, /* writepage */ - NULL, /* flushpage */ NULL, /* truncate */ proc_permission, /* permission */ }; diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 5ef59004c..5f43c691e 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -16,8 +16,6 @@ #include <linux/stat.h> #include <asm/bitops.h> -extern struct inode_operations proc_dyna_dir_inode_operations; - static ssize_t proc_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos); static ssize_t proc_file_write(struct file * file, const char * buffer, @@ -37,37 +35,10 @@ static struct file_operations proc_file_operations = { proc_file_lseek, /* lseek */ proc_file_read, /* read */ proc_file_write, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - NULL, /* ioctl */ - NULL, /* mmap */ - NULL, /* no special open code */ - NULL, /* flush */ - NULL, /* no special release code */ - NULL /* can't fsync */ }; -struct inode_operations proc_file_inode_operations = { +static struct inode_operations proc_file_inode_operations = { &proc_file_operations, /* default proc 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 @@ -101,12 +72,8 @@ proc_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) /* * 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); + n = dp->get_info(page, &start, *ppos, count); if (n < count) eof = 1; } else if (dp->read_proc) { @@ -114,7 +81,7 @@ proc_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) count, &eof, dp->data); } else break; - + if (!start) { /* * For proc files that are less than 4k @@ -221,6 +188,321 @@ static int xlate_proc_name(const char *name, return 0; } +static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0}; + +static int make_inode_number(void) +{ + int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC); + if (i<0 || i>=PROC_NDYNAMIC) + return -1; + set_bit(i, (void *) proc_alloc_map); + return PROC_DYNAMIC_FIRST + i; +} + +static int proc_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + char *s=((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data; + return vfs_readlink(dentry, buffer, buflen, s); +} + +static struct dentry *proc_follow_link(struct dentry *dentry, struct dentry *base, unsigned flags) +{ + char *s=((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data; + return vfs_follow_link(dentry, base, flags, s); +} + +static struct inode_operations proc_link_inode_operations = { + readlink: proc_readlink, + follow_link: proc_follow_link +}; + +/* + * As some entries in /proc are volatile, we want to + * get rid of unused dentries. This could be made + * smarter: we could keep a "volatile" flag in the + * inode to indicate which ones to keep. + */ +static void +proc_delete_dentry(struct dentry * dentry) +{ + d_drop(dentry); +} + +static struct dentry_operations proc_dentry_operations = +{ + NULL, /* revalidate */ + NULL, /* d_hash */ + NULL, /* d_compare */ + proc_delete_dentry /* d_delete(struct dentry *) */ +}; + +/* + * Don't create negative dentries here, return -ENOENT by hand + * instead. + */ +struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry) +{ + struct inode *inode; + struct proc_dir_entry * de; + int error; + + error = -ENOENT; + inode = NULL; + de = (struct proc_dir_entry *) dir->u.generic_ip; + if (de) { + for (de = de->subdir; de ; de = de->next) { + if (!de || !de->low_ino) + continue; + if (de->namelen != dentry->d_name.len) + continue; + if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { + int ino = de->low_ino; + error = -EINVAL; + inode = proc_get_inode(dir->i_sb, ino, de); + break; + } + } + } + + if (inode) { + dentry->d_op = &proc_dentry_operations; + d_add(dentry, inode); + return NULL; + } + return ERR_PTR(error); +} + +/* + * This returns non-zero if at EOF, so that the /proc + * root directory can use this and check if it should + * continue with the <pid> entries.. + * + * Note that the VFS-layer doesn't care about the return + * value of the readdir() call, as long as it's non-negative + * for success.. + */ +int proc_readdir(struct file * filp, + void * dirent, filldir_t filldir) +{ + struct proc_dir_entry * de; + unsigned int ino; + int i; + struct inode *inode = filp->f_dentry->d_inode; + + ino = inode->i_ino; + de = (struct proc_dir_entry *) inode->u.generic_ip; + if (!de) + return -EINVAL; + i = filp->f_pos; + switch (i) { + case 0: + if (filldir(dirent, ".", 1, i, ino) < 0) + return 0; + i++; + filp->f_pos++; + /* fall through */ + case 1: + if (filldir(dirent, "..", 2, i, + filp->f_dentry->d_parent->d_inode->i_ino + ) < 0) + return 0; + i++; + filp->f_pos++; + /* fall through */ + default: + de = de->subdir; + i -= 2; + for (;;) { + if (!de) + return 1; + if (!i) + break; + de = de->next; + i--; + } + + do { + if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino) < 0) + return 0; + filp->f_pos++; + de = de->next; + } while (de); + } + return 1; +} + +/* + * These are the generic /proc directory operations. They + * use the in-memory "struct proc_dir_entry" tree to parse + * the /proc directory. + */ +static struct file_operations proc_dir_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + proc_readdir, /* readdir */ +}; + +/* + * proc directories can do almost nothing.. + */ +struct inode_operations proc_dir_inode_operations = { + &proc_dir_operations, /* default net directory file-ops */ + NULL, /* create */ + proc_lookup, /* lookup */ +}; + +int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) +{ + int i; + + i = make_inode_number(); + if (i < 0) + return -EAGAIN; + dp->low_ino = i; + dp->next = dir->subdir; + dp->parent = dir; + dir->subdir = dp; + if (S_ISDIR(dp->mode)) { + if (dp->ops == NULL) + dp->ops = &proc_dir_inode_operations; + dir->nlink++; + } else if (S_ISLNK(dp->mode)) { + if (dp->ops == NULL) + dp->ops = &proc_link_inode_operations; + } else if (S_ISREG(dp->mode)) { + if (dp->ops == NULL) + dp->ops = &proc_file_inode_operations; + } + return 0; +} + +/* + * Kill an inode that got unregistered.. + */ +static void proc_kill_inodes(struct proc_dir_entry *de) +{ + struct list_head *p; + struct super_block *sb; + + /* + * Actually it's a partial revoke(). We have to go through all + * copies of procfs. proc_super_blocks is protected by the big + * lock for the time being. + */ + for (sb = proc_super_blocks; + sb; + sb = (struct super_block*)sb->u.generic_sbp) { + file_list_lock(); + for (p = sb->s_files.next; p != &sb->s_files; p = p->next) { + struct file * filp = list_entry(p, struct file, f_list); + struct dentry * dentry; + struct inode * inode; + + dentry = filp->f_dentry; + if (!dentry) + continue; + if (dentry->d_op != &proc_dentry_operations) + continue; + inode = dentry->d_inode; + if (!inode) + continue; + if (inode->u.generic_ip != de) + continue; + filp->f_op = NULL; + } + file_list_unlock(); + } +} + +struct proc_dir_entry *proc_symlink(const char *name, + struct proc_dir_entry *parent, char *dest) +{ + struct proc_dir_entry *ent = NULL; + const char *fn = name; + int len; + + if (!parent && xlate_proc_name(name, &parent, &fn) != 0) + goto out; + len = strlen(fn); + + ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL); + if (!ent) + goto out; + memset(ent, 0, sizeof(struct proc_dir_entry)); + memcpy(((char *) ent) + sizeof(*ent), fn, len + 1); + ent->name = ((char *) ent) + sizeof(*ent); + ent->namelen = len; + ent->nlink = 1; + ent->mode = S_IFLNK|S_IRUGO|S_IWUGO|S_IXUGO; + ent->data = kmalloc((ent->size=strlen(dest))+1, GFP_KERNEL); + if (!ent->data) { + kfree(ent); + goto out; + } + strcpy((char*)ent->data,dest); + + proc_register(parent, ent); + +out: + return ent; +} + +struct proc_dir_entry *proc_mknod(const char *name, mode_t mode, + struct proc_dir_entry *parent, kdev_t rdev) +{ + struct proc_dir_entry *ent = NULL; + const char *fn = name; + int len; + + if (!parent && xlate_proc_name(name, &parent, &fn) != 0) + goto out; + len = strlen(fn); + + ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL); + if (!ent) + goto out; + memset(ent, 0, sizeof(struct proc_dir_entry)); + memcpy(((char *) ent) + sizeof(*ent), fn, len + 1); + ent->name = ((char *) ent) + sizeof(*ent); + ent->namelen = len; + ent->nlink = 1; + ent->mode = mode; + ent->rdev = rdev; + + proc_register(parent, ent); + +out: + return ent; +} + +struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent) +{ + struct proc_dir_entry *ent = NULL; + const char *fn = name; + int len; + + if (!parent && xlate_proc_name(name, &parent, &fn) != 0) + goto out; + len = strlen(fn); + + ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL); + if (!ent) + goto out; + memset(ent, 0, sizeof(struct proc_dir_entry)); + memcpy(((char *) ent) + sizeof(*ent), fn, len + 1); + ent->name = ((char *) ent) + sizeof(*ent); + ent->namelen = len; + ent->ops = &proc_dir_inode_operations; + ent->nlink = 2; + ent->mode = S_IFDIR | S_IRUGO | S_IXUGO; + + proc_register(parent, ent); + +out: + return ent; +} + struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent) { @@ -243,7 +525,7 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, if (S_ISDIR(mode)) { if ((mode & S_IALLUGO) == 0) mode |= S_IRUGO | S_IXUGO; - ent->ops = &proc_dyna_dir_inode_operations; + ent->ops = &proc_dir_inode_operations; ent->nlink = 2; } else { if ((mode & S_IFMT) == 0) @@ -260,14 +542,16 @@ out: return ent; } -extern void free_proc_entry(struct proc_dir_entry *); void free_proc_entry(struct proc_dir_entry *de) { int ino = de->low_ino; - if (ino >= PROC_DYNAMIC_FIRST && - ino < PROC_DYNAMIC_FIRST+PROC_NDYNAMIC) - kfree(de); + if (ino < PROC_DYNAMIC_FIRST && + ino >= PROC_DYNAMIC_FIRST+PROC_NDYNAMIC) + return; + if (S_ISLNK(de->mode) && de->data) + kfree(de->data); + kfree(de); } /* @@ -276,6 +560,7 @@ void free_proc_entry(struct proc_dir_entry *de) */ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) { + struct proc_dir_entry **p; struct proc_dir_entry *de; const char *fn = name; int len; @@ -283,14 +568,17 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) if (!parent && xlate_proc_name(name, &parent, &fn) != 0) goto out; len = strlen(fn); - - for (de = parent->subdir; de ; de = de->next) { - if (proc_match(len, fn, de)) - break; - } - - if (de) { - proc_unregister(parent, de->low_ino); + for (p = &parent->subdir; *p; p=&(*p)->next ) { + if (!proc_match(len, fn, *p)) + continue; + de = *p; + *p = de->next; + de->next = NULL; + if (S_ISDIR(de->mode)) + parent->nlink--; + clear_bit(de->low_ino-PROC_DYNAMIC_FIRST, + (void *) proc_alloc_map); + proc_kill_inodes(de); de->nlink = 0; de->deleted = 1; if (!de->count) @@ -299,6 +587,7 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) printk("remove_proc_entry: %s/%s busy, count=%d\n", parent->name, de->name, de->count); } + break; } out: return; diff --git a/fs/proc/inode-alloc.txt b/fs/proc/inode-alloc.txt index 4af79966c..fbcfa4e40 100644 --- a/fs/proc/inode-alloc.txt +++ b/fs/proc/inode-alloc.txt @@ -5,7 +5,6 @@ Current inode allocations in the proc-fs (hex-numbers): 001 root-ino 00001000-00001fff dynamic entries - 00002000-00002fff openprom entries 0001xxxx-7fffxxxx pid-dir entries for pid 1-7fff 80000000-ffffffff unused diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 8842cc253..607a7d7e9 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -13,7 +13,7 @@ #include <linux/file.h> #include <linux/locks.h> #include <linux/limits.h> -#include <linux/config.h> +#define __NO_VERSION__ #include <linux/module.h> #include <asm/system.h> @@ -51,10 +51,6 @@ void de_put(struct proc_dir_entry *de) static void proc_put_inode(struct inode *inode) { -#ifdef CONFIG_SUN_OPENPROMFS_MODULE - if (PROC_INODE_OPENPROM(inode) && proc_openprom_use) - (*proc_openprom_use)(inode, 0); -#endif /* * Kill off unused inodes ... VFS will unhash and * delete the inode if we set i_nlink to zero. @@ -74,9 +70,6 @@ static void proc_delete_inode(struct inode *inode) proc_pid_delete_inode(inode); return; } - if (PROC_INODE_OPENPROM(inode)) - return; - if (de) { if (de->owner) __MOD_DEC_USE_COUNT(de->owner); @@ -97,6 +90,30 @@ static void proc_put_super(struct super_block *sb) *p = (struct super_block *)(*p)->u.generic_sbp; } +static void proc_write_inode(struct inode * inode) +{ +} + +static void proc_read_inode(struct inode * inode) +{ + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; +} + +static int proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) +{ + struct statfs tmp; + + tmp.f_type = PROC_SUPER_MAGIC; + tmp.f_bsize = PAGE_SIZE/sizeof(long); + tmp.f_blocks = 0; + tmp.f_bfree = 0; + tmp.f_bavail = 0; + tmp.f_files = 0; + tmp.f_ffree = 0; + tmp.f_namelen = NAME_MAX; + return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; +} + static struct super_operations proc_sops = { proc_read_inode, proc_write_inode, @@ -158,11 +175,6 @@ printk("proc_iget: using deleted entry %s, count=%d\n", de->name, de->count); if (!inode) goto out_fail; -#ifdef CONFIG_SUN_OPENPROMFS_MODULE - if (PROC_INODE_OPENPROM(inode) && proc_openprom_use) - (*proc_openprom_use)(inode, 1); -#endif - inode->u.generic_ip = (void *) de; if (de) { if (de->mode) { @@ -172,26 +184,16 @@ printk("proc_iget: using deleted entry %s, count=%d\n", de->name, de->count); } if (de->size) inode->i_size = de->size; - if (de->ops) - inode->i_op = de->ops; if (de->nlink) inode->i_nlink = de->nlink; if (de->owner) __MOD_INC_USE_COUNT(de->owner); + if (S_ISBLK(de->mode)||S_ISCHR(de->mode)||S_ISFIFO(de->mode)) + init_special_inode(inode,de->mode,kdev_t_to_nr(de->rdev)); + else if (de->ops) + inode->i_op = de->ops; } - /* - * Fixup the root inode's nlink value - */ - if (inode->i_ino == PROC_ROOT_INO) { - struct task_struct *p; - read_lock(&tasklist_lock); - for_each_task(p) { - if (p->pid) - inode->i_nlink++; - } - read_unlock(&tasklist_lock); - } out: return inode; @@ -204,6 +206,7 @@ struct super_block *proc_read_super(struct super_block *s,void *data, int silent) { struct inode * root_inode; + struct task_struct *p; lock_super(s); s->s_blocksize = 1024; @@ -213,6 +216,12 @@ struct super_block *proc_read_super(struct super_block *s,void *data, root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); if (!root_inode) goto out_no_root; + /* + * Fixup the root inode's nlink value + */ + read_lock(&tasklist_lock); + for_each_task(p) if (p->pid) root_inode->i_nlink++; + read_unlock(&tasklist_lock); s->s_root = d_alloc_root(root_inode); if (!s->s_root) goto out_no_root; @@ -229,27 +238,3 @@ out_no_root: unlock_super(s); return NULL; } - -int proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) -{ - struct statfs tmp; - - tmp.f_type = PROC_SUPER_MAGIC; - tmp.f_bsize = PAGE_SIZE/sizeof(long); - tmp.f_blocks = 0; - tmp.f_bfree = 0; - tmp.f_bavail = 0; - tmp.f_files = 0; - tmp.f_ffree = 0; - tmp.f_namelen = NAME_MAX; - return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; -} - -void proc_read_inode(struct inode * inode) -{ - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; -} - -void proc_write_inode(struct inode * inode) -{ -} diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index ec2a92db3..28635ff14 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c @@ -3,9 +3,9 @@ * * Modelled on fs/exec.c:aout_core_dump() * Jeremy Fitzhardinge <jeremy@sw.oz.au> - * Implemented by David Howells <David.Howells@nexor.co.uk> + * ELF version written 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> + * Support to dump vmalloc'd areas (ELF only), Tigran Aivazian <tigran@sco.com> */ #include <linux/config.h> @@ -16,7 +16,6 @@ #include <linux/elf.h> #include <linux/elfcore.h> #include <linux/vmalloc.h> -#include <linux/proc_fs.h> #include <asm/uaccess.h> @@ -43,8 +42,7 @@ struct inode_operations proc_kcore_inode_operations = { }; #ifdef CONFIG_KCORE_AOUT -static ssize_t read_kcore(struct file * file, char * buf, - size_t count, loff_t *ppos) +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; @@ -79,7 +77,8 @@ static ssize_t read_kcore(struct file * file, char * buf, if (p + count1 > sizeof(struct user)) count1 = sizeof(struct user)-p; pnt = (char *) &dump + p; - copy_to_user(buf,(void *) pnt, count1); + if (copy_to_user(buf,(void *) pnt, count1)) + return -EFAULT; buf += count1; p += count1; count -= count1; @@ -90,14 +89,16 @@ static ssize_t read_kcore(struct file * file, char * buf, count1 = PAGE_SIZE + FIRST_MAPPED - p; if (count1 > count) count1 = count; - clear_user(buf, count1); + if (clear_user(buf, count1)) + return -EFAULT; buf += count1; p += count1; count -= count1; read += count1; } if (count > 0) { - copy_to_user(buf, (void *) (PAGE_OFFSET+p-PAGE_SIZE), count); + if (copy_to_user(buf, (void *) (PAGE_OFFSET+p-PAGE_SIZE), count)) + return -EFAULT; read += count; } *ppos += read; @@ -130,6 +131,8 @@ static size_t get_kcore_size(int *num_vma, int *elf_buflen) } for (m=vmlist; m; m=m->next) { + if (m->flags & VM_IOREMAP) /* don't dump ioremap'd stuff! (TA) */ + continue; try = (size_t)m->addr + m->size; if (try > size) size = try; @@ -189,7 +192,7 @@ static char *storenote(struct memelfnote *men, char *bufp) * 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) +static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff) { struct elf_prstatus prstatus; /* NT_PRSTATUS */ struct elf_prpsinfo prpsinfo; /* NT_PRPSINFO */ @@ -235,28 +238,33 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int elf_buflen) nhdr->p_flags = 0; nhdr->p_align = 0; - /* setup ELF PT_LOAD program header */ + /* setup ELF PT_LOAD program header for the + * virtual range 0xc0000000 -> high_memory */ 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_offset = dataoff; 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; + /* setup ELF PT_LOAD program header for every vmalloc'd area */ for (m=vmlist; m; m=m->next) { + if (m->flags & VM_IOREMAP) /* don't dump ioremap'd stuff! (TA) */ + continue; + 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_offset = (size_t)m->addr - PAGE_OFFSET + dataoff; phdr->p_vaddr = (size_t)m->addr; - phdr->p_paddr = __pa(m); + phdr->p_paddr = __pa(m->addr); phdr->p_filesz = phdr->p_memsz = m->size; phdr->p_align = PAGE_SIZE; } @@ -310,13 +318,12 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int elf_buflen) /* * 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) +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; + size_t elf_buflen; + int num_vma; /* XXX we need to somehow lock vmlist between here * and after elf_kcore_store_hdr() returns. @@ -332,16 +339,21 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, /* construct an ELF core header if we'll need some of it */ if (*fpos < elf_buflen) { + char * elf_buf; + tsz = elf_buflen - *fpos; if (buflen < tsz) tsz = buflen; - elf_buffer = kmalloc(elf_buflen, GFP_KERNEL); - if (!elf_buffer) + elf_buf = kmalloc(elf_buflen, GFP_ATOMIC); + if (!elf_buf) 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); + memset(elf_buf, 0, elf_buflen); + elf_kcore_store_hdr(elf_buf, num_vma, elf_buflen); + if (copy_to_user(buffer, elf_buf + *fpos, tsz)) { + kfree(elf_buf); + return -EFAULT; + } + kfree(elf_buf); buflen -= tsz; *fpos += tsz; buffer += tsz; @@ -349,7 +361,7 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, /* leave now if filled buffer already */ if (buflen == 0) - return tsz; + return acc; } /* where page 0 not mapped, write zeros into buffer */ @@ -361,7 +373,8 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, tsz = buflen; /* write zeros to buffer */ - clear_user(buffer, tsz); + if (clear_user(buffer, tsz)) + return -EFAULT; buflen -= tsz; *fpos += tsz; buffer += tsz; @@ -372,17 +385,12 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, 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 + if (copy_to_user(buffer, __va(*fpos - elf_buflen), buflen)) + return -EFAULT; + acc += buflen; *fpos += buflen; - return acc; - } #endif /* CONFIG_KCORE_AOUT */ diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c index bfe6c8c2e..b9344ba55 100644 --- a/fs/proc/kmsg.c +++ b/fs/proc/kmsg.c @@ -61,23 +61,4 @@ static struct file_operations proc_kmsg_operations = { struct inode_operations proc_kmsg_inode_operations = { &proc_kmsg_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/omirr.c b/fs/proc/omirr.c index f738827a7..f205dd753 100644 --- a/fs/proc/omirr.c +++ b/fs/proc/omirr.c @@ -278,23 +278,4 @@ static struct file_operations omirr_operations = { struct inode_operations proc_omirr_inode_operations = { &omirr_operations, - 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/openprom-dev.c b/fs/proc/openprom-dev.c new file mode 100644 index 000000000..79ef8d549 --- /dev/null +++ b/fs/proc/openprom-dev.c @@ -0,0 +1,46 @@ +/* + * linux/fs/proc/openprom-dev.c + * + * handling of devices attached to openpromfs. + */ + +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/proc_fs.h> +#include <linux/stat.h> +#include <linux/config.h> +#include <linux/init.h> +#include <linux/module.h> + +struct openpromfs_dev *openprom_devices = NULL; +static ino_t openpromdev_ino = PROC_OPENPROMD_FIRST; + +int proc_openprom_regdev(struct openpromfs_dev *d) +{ + if (openpromdev_ino == PROC_OPENPROMD_FIRST + PROC_NOPENPROMD) + return -1; + d->next = openprom_devices; + d->inode = openpromdev_ino++; + openprom_devices = d; + return 0; +} + +int proc_openprom_unregdev(struct openpromfs_dev *d) +{ + if (d == openprom_devices) { + openprom_devices = d->next; + } else if (!openprom_devices) + return -1; + else { + struct openpromfs_dev *p; + + for (p = openprom_devices; p->next != d && p->next; p = p->next); + if (!p->next) return -1; + p->next = d->next; + } + return 0; +} + +#if defined(CONFIG_SUN_OPENPROMFS_MODULE) +EXPORT_SYMBOL(openprom_devices); +#endif diff --git a/fs/proc/openpromfs.c b/fs/proc/openpromfs.c index c9553ea24..55f290664 100644 --- a/fs/proc/openpromfs.c +++ b/fs/proc/openpromfs.c @@ -50,8 +50,7 @@ static u16 options = 0xffff; static u16 aliases = 0xffff; static int aliases_nodes = 0; static char *alias_names [ALIASES_NNODES]; -static struct inode_operations *proc_openprom_iops = 0; -static struct openpromfs_dev **devices; +extern struct openpromfs_dev *openprom_devices; #define NODE(ino) nodes[ino - PROC_OPENPROM_FIRST] #define NODE2INO(node) (node + PROC_OPENPROM_FIRST) @@ -566,25 +565,6 @@ static struct file_operations openpromfs_prop_ops = { static struct inode_operations openpromfs_prop_inode_ops = { &openpromfs_prop_ops, /* default property 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 struct file_operations openpromfs_nodenum_ops = { @@ -603,25 +583,6 @@ static struct file_operations openpromfs_nodenum_ops = { static struct inode_operations openpromfs_nodenum_inode_ops = { &openpromfs_nodenum_ops,/* default .node 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 struct file_operations openprom_alias_operations = { @@ -654,13 +615,13 @@ static struct inode_operations openprom_alias_inode_operations = { NULL, /* get_block */ NULL, /* readpage */ NULL, /* writepage */ - NULL, /* flushpage */ NULL, /* truncate */ NULL, /* permission */ - NULL, /* smap */ NULL /* revalidate */ }; +extern struct inode_operations openprom_inode_operations; + static int lookup_children(u16 n, const char * name, int len) { int ret; @@ -772,7 +733,7 @@ static struct dentry *openpromfs_lookup(struct inode * dir, struct dentry *dentr } } if (!ino) { - for (d = *devices; d; d = d->next) + for (d = openprom_devices; d; d = d->next) if ((d->node == n) && (strlen (d->name) == len) && !strncmp (d->name, name, len)) { ino = d->inode; @@ -787,7 +748,7 @@ static struct dentry *openpromfs_lookup(struct inode * dir, struct dentry *dentr else return ERR_PTR(-ENOENT); } - inode = proc_get_inode (dir->i_sb, ino, 0); + inode = iget (dir->i_sb, ino, 0); if (!inode) return ERR_PTR(-EINVAL); switch (type) { @@ -797,7 +758,7 @@ static struct dentry *openpromfs_lookup(struct inode * dir, struct dentry *dentr inode->i_mode |= S_IWUSR; inode->i_op = &openprom_alias_inode_operations; } else - inode->i_op = proc_openprom_iops; + inode->i_op = &openprom_inode_operations; inode->i_nlink = 2; break; case OPFSL_NODENUM: @@ -825,11 +786,7 @@ static struct dentry *openpromfs_lookup(struct inode * dir, struct dentry *dentr (((u16)(ino - NODEP2INO(NODE(dir->i_ino).first_prop) - 1)) << 16)); break; case OPFSL_DEVICE: - inode->i_mode = d->mode; - inode->i_op = &chrdev_inode_operations; - inode->i_nlink = 1; - inode->i_rdev = d->rdev; - break; + init_special_inode(d->mode, kdev_to_nr(d->rdev)); } inode->i_gid = 0; @@ -914,7 +871,7 @@ static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filld } } } - for (d = *devices; d; d = d->next) { + for (d = openprom_devices; d; d = d->next) { if (d->node == n) { if (i) i--; else { @@ -947,9 +904,8 @@ static int openpromfs_create (struct inode *dir, struct dentry *dentry, int mode strncpy (p, dentry->d_name.name, dentry->d_name.len); p [dentry->d_name.len] = 0; alias_names [aliases_nodes++] = p; - inode = proc_get_inode (dir->i_sb, - NODEP2INO(NODE(dir->i_ino).first_prop) - + aliases_nodes, 0); + inode = iget (dir->i_sb, + NODEP2INO(NODE(dir->i_ino).first_prop) + aliases_nodes); if (!inode) return -EINVAL; inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR; @@ -1090,25 +1046,6 @@ void openpromfs_use (struct inode *inode, int inc) { static int root_fresh = 1; static int dec_first = 1; -#ifdef OPENPROM_DEBUGGING - static int usec = 0; - - if (inc) { - if (inode->i_count == 1) - usec++; - else if (root_fresh && inode->i_ino == PROC_OPENPROM_FIRST) { - root_fresh = 0; - usec++; - } - } else { - if (inode->i_ino == PROC_OPENPROM_FIRST) - root_fresh = 0; - if (!dec_first) - usec--; - } - printk ("openpromfs_use: %d %d %d %d\n", - inode->i_ino, inc, usec, inode->i_count); -#else if (inc) { if (inode->i_count == 1) MOD_INC_USE_COUNT; @@ -1122,7 +1059,6 @@ void openpromfs_use (struct inode *inode, int inc) if (!dec_first) MOD_DEC_USE_COUNT; } -#endif dec_first = 0; } @@ -1130,39 +1066,131 @@ void openpromfs_use (struct inode *inode, int inc) #define openpromfs_use 0 #endif -#ifndef MODULE -#define RET(x) -void __init openpromfs_init (void) -#else +static struct file_operations openprom_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + openpromfs_readdir, /* readdir */ +}; -EXPORT_NO_SYMBOLS; +static struct inode_operations openprom_inode_operations = { + &openprom_operations,/* default net directory file-ops */ + NULL, /* create */ + openpromfs_lookup, /* lookup */ +}; -#define RET(x) -x -int init_module (void) -#endif +static void openprom_read_inode(struct inode * inode) +{ + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + if (inode->i_ino == PROC_OPENPROM) { + inode->i_op = &openprom_inode_operations; + } +} + +static void openprom_put_super(struct super_block *sb) +{ + MOD_DEC_USE_COUNT; +} + +static int openprom_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) +{ + struct statfs tmp; + + tmp.f_type = PROC_SUPER_MAGIC; /* FIXME */ + tmp.f_bsize = PAGE_SIZE/sizeof(long); /* ??? */ + tmp.f_blocks = 0; + tmp.f_bfree = 0; + tmp.f_bavail = 0; + tmp.f_files = 0; + tmp.f_ffree = 0; + tmp.f_namelen = NAME_MAX; + return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; +} + +static struct super_operations openprom_sops = { + openprom_read_inode, + NULL, + NULL, + NULL, + NULL, + openprom_put_super, + NULL, + openprom_statfs, + NULL +}; + +struct super_block *openprom_read_super(struct super_block *s,void *data, + int silent) +{ + struct inode * root_inode; + + MOD_INC_USE_COUNT; + lock_super(s); + s->s_blocksize = 1024; + s->s_blocksize_bits = 10; + s->s_magic = PROC_SUPER_MAGIC; /* FIXME */ + s->s_op = &openprom_sops; + root_inode = iget(s, PROC_OPENPROM); + if (!root_inode) + goto out_no_root; + s->s_root = d_alloc_root(root_inode); + if (!s->s_root) + goto out_no_root; + unlock_super(s); + return s; + +out_no_root: + printk("proc_read_super: get root inode failed\n"); + iput(root_inode); + s->s_dev = 0; + unlock_super(s); + return NULL; +} + +static struct file_system_type openprom_fs_type = { + "openprom", + 0, + openprom_read_super, + NULL +}; + +static int init_openprom_fs(void) { nodes = (openpromfs_node *)__get_free_pages(GFP_KERNEL, 0); if (!nodes) { printk (KERN_WARNING "/proc/openprom: can't get free page\n"); - return RET(EIO); + return -EIO; } if (get_nodes (0xffff, prom_root_node) == 0xffff) { printk (KERN_WARNING "/proc/openprom: couldn't setup tree\n"); - return RET(EIO); + return -EIO; } nodes[last_node].first_prop = first_prop; - proc_openprom_iops = proc_openprom_register (openpromfs_readdir, - openpromfs_lookup, - openpromfs_use, - &devices); - return RET(0); + return register_filesystem(&openprom_fs_type); +} + +#ifdef MODULE + +EXPORT_NO_SYMBOLS; + +int init_module (void) +{ + return init_openprom_fs(); +} + +#else + +void __init openpromfs_init (void) +{ + init_openprom_fs(); } +#endif #ifdef MODULE void cleanup_module (void) { int i; - proc_openprom_deregister (); + unregister_filesystem(&openprom_fs_type); free_pages ((unsigned long)nodes, alloced); for (i = 0; i < aliases_nodes; i++) if (alias_names [i]) diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index c06a802ce..1b4b7f23b 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c @@ -41,62 +41,6 @@ static int property_read_proc(char *page, char **start, off_t off, * and "@10" to it. */ -static int devtree_readlink(struct dentry *, char *, int); -static struct dentry *devtree_follow_link(struct dentry *, struct dentry *, unsigned int); - -struct inode_operations devtree_symlink_inode_operations = { - NULL, /* no file-operations */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - devtree_readlink, /* readlink */ - devtree_follow_link, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* flushpage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL, /* smap */ - NULL /* revalidate */ -}; - -static struct dentry *devtree_follow_link(struct dentry *dentry, - struct dentry *base, - unsigned int follow) -{ - struct inode *inode = dentry->d_inode; - struct proc_dir_entry * de; - char *link; - - de = (struct proc_dir_entry *) inode->u.generic_ip; - link = (char *) de->data; - return lookup_dentry(link, base, follow); -} - -static int devtree_readlink(struct dentry *dentry, char *buffer, int buflen) -{ - struct inode *inode = dentry->d_inode; - struct proc_dir_entry * de; - char *link; - int linklen; - - de = (struct proc_dir_entry *) inode->u.generic_ip; - link = (char *) de->data; - linklen = strlen(link); - if (linklen > buflen) - linklen = buflen; - if (copy_to_user(buffer, link, linklen)) - return -EFAULT; - return linklen; -} - /* * Process a node, adding entries for its children and its properties. */ @@ -115,18 +59,11 @@ static void add_node(struct device_node *np, struct proc_dir_entry *de) * Unfortunately proc_register puts each new entry * at the beginning of the list. So we rearrange them. */ - ent = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL); + ent = create_proc_read_entry(de, 0, pp->name, + property_read_proc, pp); if (ent == 0) break; - memset(ent, 0, sizeof(struct proc_dir_entry)); - ent->name = pp->name; - ent->namelen = strlen(pp->name); - ent->mode = S_IFREG | S_IRUGO; - ent->nlink = 1; - ent->data = pp; - ent->read_proc = property_read_proc; ent->size = pp->length; - proc_register(de, ent); *lastp = ent; lastp = &ent->next; } @@ -140,15 +77,9 @@ static void add_node(struct device_node *np, struct proc_dir_entry *de) l = strlen(p); if (l > 2 && p[l-2] == '@' && p[l-1] == '0') l -= 2; - ent = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL); + ent = proc_mkdir(de, p); if (ent == 0) break; - memset(ent, 0, sizeof(struct proc_dir_entry)); - ent->name = p; - ent->namelen = l; - ent->mode = S_IFDIR | S_IRUGO | S_IXUGO; - ent->nlink = 2; - proc_register(de, ent); *lastp = ent; lastp = &ent->next; add_node(child, ent); @@ -168,18 +99,9 @@ static void add_node(struct device_node *np, struct proc_dir_entry *de) if (sib->name && strcmp(sib->name, child->name) == 0) break; if (sib == child && strncmp(p, child->name, l) != 0) { - al = kmalloc(sizeof(struct proc_dir_entry), - GFP_KERNEL); + al = proc_symlink(de, child->name, ent->name); if (al == 0) break; - memset(al, 0, sizeof(struct proc_dir_entry)); - al->name = child->name; - al->namelen = strlen(child->name); - al->mode = S_IFLNK | S_IRUGO | S_IXUGO; - al->nlink = 1; - al->data = (void *) ent->name; - al->ops = &devtree_symlink_inode_operations; - proc_register(de, al); *lastp = al; lastp = &al->next; } @@ -187,16 +109,9 @@ static void add_node(struct device_node *np, struct proc_dir_entry *de) /* * Add another directory with the @address part as its name. */ - al = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL); + al = proc_symlink(de, at, ent->name); if (al == 0) break; - memset(al, 0, sizeof(struct proc_dir_entry)); - al->name = at; - al->namelen = strlen(at); - al->mode = S_IFLNK | S_IRUGO | S_IXUGO; - al->nlink = 1; - al->data = (void *) ent->name; - al->ops = &devtree_symlink_inode_operations; proc_register(de, al); *lastp = al; lastp = &al->next; @@ -213,7 +128,7 @@ void proc_device_tree_init(void) struct device_node *root; if ( !have_of ) return; - proc_device_tree = create_proc_entry("device-tree", S_IFDIR, 0); + proc_device_tree = proc_mkdir("device-tree", 0); if (proc_device_tree == 0) return; root = find_path_device("/"); diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 97f74a028..00b09e6a7 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -60,7 +60,6 @@ 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 @@ -453,20 +452,6 @@ static int cmdline_read_proc(char *page, char **start, off_t off, 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) @@ -665,9 +650,6 @@ void proc_misc_init(void) {"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 diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c index 4b4ca41b8..e241c938e 100644 --- a/fs/proc/proc_tty.c +++ b/fs/proc/proc_tty.c @@ -161,10 +161,9 @@ void proc_tty_unregister_driver(struct tty_driver *driver) if (!ent) return; - proc_unregister(proc_tty_driver, ent->low_ino); + remove_proc_entry(driver->driver_name, proc_tty_driver); driver->proc_entry = 0; - kfree(ent); } /* @@ -172,18 +171,11 @@ void proc_tty_unregister_driver(struct tty_driver *driver) */ void __init proc_tty_init(void) { - struct proc_dir_entry *ent; - - ent = create_proc_entry("tty", S_IFDIR, 0); - if (!ent) + if (!proc_mkdir("tty", 0)) return; - proc_tty_ldisc = create_proc_entry("tty/ldisc", S_IFDIR, 0); - proc_tty_driver = create_proc_entry("tty/driver", S_IFDIR, 0); + proc_tty_ldisc = proc_mkdir("tty/ldisc", 0); + proc_tty_driver = proc_mkdir("tty/driver", 0); - ent = create_proc_entry("tty/ldiscs", 0, 0); - ent->read_proc = tty_ldiscs_read_proc; - - ent = create_proc_entry("tty/drivers", 0, 0); - ent->read_proc = tty_drivers_read_proc; + create_proc_read_entry("tty/ldiscs", 0, 0, tty_ldiscs_read_proc,NULL); + create_proc_read_entry("tty/drivers", 0, 0, tty_drivers_read_proc,NULL); } - diff --git a/fs/proc/procfs_syms.c b/fs/proc/procfs_syms.c index fa2ee362e..7c986d615 100644 --- a/fs/proc/procfs_syms.c +++ b/fs/proc/procfs_syms.c @@ -8,22 +8,16 @@ extern struct proc_dir_entry *proc_sys_root; #ifdef CONFIG_SYSCTL EXPORT_SYMBOL(proc_sys_root); #endif -EXPORT_SYMBOL(proc_register); -EXPORT_SYMBOL(proc_unregister); +EXPORT_SYMBOL(proc_symlink); +EXPORT_SYMBOL(proc_mknod); +EXPORT_SYMBOL(proc_mkdir); EXPORT_SYMBOL(create_proc_entry); EXPORT_SYMBOL(remove_proc_entry); EXPORT_SYMBOL(proc_root); EXPORT_SYMBOL(proc_root_fs); -EXPORT_SYMBOL(proc_get_inode); -EXPORT_SYMBOL(proc_dir_inode_operations); EXPORT_SYMBOL(proc_net); EXPORT_SYMBOL(proc_bus); -#if defined(CONFIG_SUN_OPENPROMFS_MODULE) -EXPORT_SYMBOL(proc_openprom_register); -EXPORT_SYMBOL(proc_openprom_deregister); -#endif - static struct file_system_type proc_fs_type = { "proc", 0 /* FS_NO_DCACHE doesn't work correctly */, diff --git a/fs/proc/root.c b/fs/proc/root.c index b87b0fb4f..83a0d7619 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -15,383 +15,21 @@ #include <linux/config.h> #include <linux/init.h> #include <asm/bitops.h> -#ifdef CONFIG_KMOD -#include <linux/kmod.h> -#endif -#ifdef CONFIG_ZORRO -#include <linux/zorro.h> -#endif - -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 *); - -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. - */ -static struct file_operations proc_dir_operations = { - NULL, /* lseek - default */ - NULL, /* read - bad */ - NULL, /* write - bad */ - proc_readdir, /* readdir */ -}; - -/* - * proc directories can do almost nothing.. - */ -struct inode_operations proc_dir_inode_operations = { - &proc_dir_operations, /* default net directory file-ops */ - NULL, /* create */ - proc_lookup, /* lookup */ -}; - -/* - * /proc dynamic directories now support unlinking - */ -struct inode_operations proc_dyna_dir_inode_operations = { - &proc_dir_operations, /* default proc dir ops */ - NULL, /* create */ - proc_lookup, /* lookup */ - NULL, /* link */ - proc_unlink, /* unlink(struct inode *, struct dentry *) */ -}; - -/* - * The root /proc directory is special, as it has the - * <pid> directories. Thus we don't use the generic - * directory handling functions for that.. - */ -static struct file_operations proc_root_operations = { - NULL, /* lseek - default */ - NULL, /* read - bad */ - NULL, /* write - bad */ - proc_root_readdir, /* readdir */ -}; - -/* - * proc root can do almost nothing.. - */ -static struct inode_operations proc_root_inode_operations = { - &proc_root_operations, /* default base directory file-ops */ - NULL, /* create */ - proc_root_lookup, /* lookup */ -}; - -/* - * This is the root "inode" in the /proc tree.. - */ -struct proc_dir_entry proc_root = { - PROC_ROOT_INO, 5, "/proc", - S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, - 0, &proc_root_inode_operations, - NULL, NULL, - NULL, - &proc_root, NULL -}; struct proc_dir_entry *proc_net, *proc_bus, *proc_root_fs, *proc_root_driver; -#ifdef CONFIG_MCA -struct proc_dir_entry *proc_mca; -#endif - #ifdef CONFIG_SYSCTL struct proc_dir_entry *proc_sys_root; #endif -#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) - -static int (*proc_openprom_defreaddir_ptr)(struct file *, void *, filldir_t); -static struct dentry * (*proc_openprom_deflookup_ptr)(struct inode *, struct dentry *); -void (*proc_openprom_use)(struct inode *, int) = 0; -static struct openpromfs_dev *proc_openprom_devices = NULL; -static ino_t proc_openpromdev_ino = PROC_OPENPROMD_FIRST; - -struct inode_operations * -proc_openprom_register(int (*readdir)(struct file *, void *, filldir_t), - struct dentry * (*lookup)(struct inode *, struct dentry *), - void (*use)(struct inode *, int), - struct openpromfs_dev ***devices) -{ - proc_openprom_defreaddir_ptr = (proc_openprom_inode_operations.default_file_ops)->readdir; - proc_openprom_deflookup_ptr = proc_openprom_inode_operations.lookup; - (proc_openprom_inode_operations.default_file_ops)->readdir = readdir; - proc_openprom_inode_operations.lookup = lookup; - proc_openprom_use = use; - *devices = &proc_openprom_devices; - return &proc_openprom_inode_operations; -} - -int proc_openprom_regdev(struct openpromfs_dev *d) -{ - if (proc_openpromdev_ino == PROC_OPENPROMD_FIRST + PROC_NOPENPROMD) - return -1; - d->next = proc_openprom_devices; - d->inode = proc_openpromdev_ino++; - proc_openprom_devices = d; - return 0; -} - -int proc_openprom_unregdev(struct openpromfs_dev *d) -{ - if (d == proc_openprom_devices) { - proc_openprom_devices = d->next; - } else if (!proc_openprom_devices) - return -1; - else { - struct openpromfs_dev *p; - - for (p = proc_openprom_devices; p->next != d && p->next; p = p->next); - if (!p->next) return -1; - p->next = d->next; - } - return 0; -} - -#ifdef CONFIG_SUN_OPENPROMFS_MODULE -void -proc_openprom_deregister(void) -{ - (proc_openprom_inode_operations.default_file_ops)->readdir = proc_openprom_defreaddir_ptr; - proc_openprom_inode_operations.lookup = proc_openprom_deflookup_ptr; - proc_openprom_use = 0; -} -#endif - -#if defined(CONFIG_SUN_OPENPROMFS_MODULE) && defined(CONFIG_KMOD) -static int -proc_openprom_defreaddir(struct file * filp, void * dirent, filldir_t filldir) -{ - request_module("openpromfs"); - if ((proc_openprom_inode_operations.default_file_ops)->readdir != - proc_openprom_defreaddir) - return (proc_openprom_inode_operations.default_file_ops)->readdir - (filp, dirent, filldir); - return -EINVAL; -} -#define OPENPROM_DEFREADDIR proc_openprom_defreaddir - -static struct dentry * -proc_openprom_deflookup(struct inode * dir, struct dentry *dentry) -{ - request_module("openpromfs"); - if (proc_openprom_inode_operations.lookup != - proc_openprom_deflookup) - return proc_openprom_inode_operations.lookup - (dir, dentry); - return ERR_PTR(-ENOENT); -} -#define OPENPROM_DEFLOOKUP proc_openprom_deflookup -#else -#define OPENPROM_DEFREADDIR NULL -#define OPENPROM_DEFLOOKUP NULL -#endif - -static struct file_operations proc_openprom_operations = { - NULL, /* lseek - default */ - NULL, /* read - bad */ - NULL, /* write - bad */ - OPENPROM_DEFREADDIR, /* readdir */ -}; - -struct inode_operations proc_openprom_inode_operations = { - &proc_openprom_operations,/* default net directory file-ops */ - NULL, /* create */ - OPENPROM_DEFLOOKUP, /* lookup */ -}; - -struct proc_dir_entry proc_openprom = { - PROC_OPENPROM, 8, "openprom", - S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, - 0, &proc_openprom_inode_operations, - NULL, NULL, - NULL, - &proc_root, NULL -}; - -extern void openpromfs_init (void); -#endif /* CONFIG_SUN_OPENPROMFS */ - -static int make_inode_number(void) -{ - int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC); - if (i<0 || i>=PROC_NDYNAMIC) - return -1; - set_bit(i, (void *) proc_alloc_map); - 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; - - if (dp->low_ino == 0) { - i = make_inode_number(); - if (i < 0) - return -EAGAIN; - dp->low_ino = i; - } - dp->next = dir->subdir; - dp->parent = dir; - dir->subdir = dp; - if (S_ISDIR(dp->mode)) { - if (dp->ops == NULL) - dp->ops = &proc_dir_inode_operations; - dir->nlink++; - } else if (S_ISLNK(dp->mode)) { - if (dp->ops == NULL) - dp->ops = &proc_link_inode_operations; - } else { - if (dp->ops == NULL) - dp->ops = &proc_file_inode_operations; - } - return 0; -} - -/* - * Kill an inode that got unregistered.. - */ -static void proc_kill_inodes(int ino) -{ - struct list_head *p; - struct super_block *sb; - - /* - * Actually it's a partial revoke(). We have to go through all - * copies of procfs. proc_super_blocks is protected by the big - * lock for the time being. - */ - for (sb = proc_super_blocks; - sb; - sb = (struct super_block*)sb->u.generic_sbp) { - file_list_lock(); - for (p = sb->s_files.next; p != &sb->s_files; p = p->next) { - struct file * filp = list_entry(p, struct file, f_list); - struct dentry * dentry; - struct inode * inode; - - dentry = filp->f_dentry; - if (!dentry) - continue; - if (dentry->d_op != &proc_dentry_operations) - continue; - inode = dentry->d_inode; - if (!inode) - continue; - if (inode->i_ino != ino) - continue; - filp->f_op = NULL; - } - file_list_unlock(); - } -} - -int proc_unregister(struct proc_dir_entry * dir, int ino) -{ - struct proc_dir_entry **p = &dir->subdir, *dp; - - while ((dp = *p) != NULL) { - if (dp->low_ino == ino) { - *p = dp->next; - dp->next = NULL; - if (S_ISDIR(dp->mode)) - dir->nlink--; - if (ino >= PROC_DYNAMIC_FIRST && - ino < PROC_DYNAMIC_FIRST+PROC_NDYNAMIC) - clear_bit(ino-PROC_DYNAMIC_FIRST, - (void *) proc_alloc_map); - proc_kill_inodes(ino); - return 0; - } - p = &dp->next; - } - return -EINVAL; -} - /* * /proc/self: */ static int proc_self_readlink(struct dentry *dentry, char *buffer, int buflen) { - int len; char tmp[30]; - - len = sprintf(tmp, "%d", current->pid); - if (buflen < len) - len = buflen; - copy_to_user(buffer, tmp, len); - return len; + sprintf(tmp, "%d", current->pid); + return vfs_readlink(dentry,buffer,buflen,tmp); } static struct dentry * proc_self_follow_link(struct dentry *dentry, @@ -399,32 +37,13 @@ static struct dentry * proc_self_follow_link(struct dentry *dentry, unsigned int follow) { char tmp[30]; - sprintf(tmp, "%d", current->pid); - return lookup_dentry(tmp, base, follow); + return vfs_follow_link(dentry,base,follow,tmp); } static struct inode_operations proc_self_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_self_readlink, /* readlink */ - proc_self_follow_link, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* flushpage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL, /* smap */ - NULL /* revalidate */ + readlink: proc_self_readlink, + follow_link: proc_self_follow_link }; static struct proc_dir_entry proc_root_self = { @@ -435,7 +54,7 @@ static struct proc_dir_entry proc_root_self = { #ifdef __powerpc__ static struct proc_dir_entry proc_root_ppc_htab = { 0, 8, "ppc_htab", - S_IFREG | S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, 1, 0, 0, + S_IFREG | S_IRUGO|S_IWUSR, 1, 0, 0, 0, &proc_ppc_htab_inode_operations, }; #endif @@ -444,23 +63,21 @@ void __init proc_root_init(void) { proc_misc_init(); proc_register(&proc_root, &proc_root_self); - proc_net = create_proc_entry("net", S_IFDIR, 0); + proc_net = proc_mkdir("net", 0); #ifdef CONFIG_SYSVIPC - create_proc_entry("sysvipc", S_IFDIR, 0); + proc_mkdir("sysvipc", 0); #endif #ifdef CONFIG_SYSCTL - proc_sys_root = create_proc_entry("sys", S_IFDIR, 0); + proc_sys_root = proc_mkdir("sys", 0); #endif -#ifdef CONFIG_MCA - proc_mca = create_proc_entry("mca", S_IFDIR, 0); -#endif - proc_root_fs = create_proc_entry("fs", S_IFDIR, 0); - proc_root_driver = create_proc_entry("driver", S_IFDIR, 0); + proc_root_fs = proc_mkdir("fs", 0); + proc_root_driver = proc_mkdir("driver", 0); #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) #ifdef CONFIG_SUN_OPENPROMFS openpromfs_init (); #endif - proc_register(&proc_root, &proc_openprom); + /* just give it a mountpoint */ + proc_mkdir("openprom", 0); #endif proc_tty_init(); #ifdef __powerpc__ @@ -469,63 +86,7 @@ void __init proc_root_init(void) #ifdef CONFIG_PROC_DEVICETREE proc_device_tree_init(); #endif - proc_bus = create_proc_entry("bus", S_IFDIR, 0); -} - -/* - * As some entries in /proc are volatile, we want to - * get rid of unused dentries. This could be made - * smarter: we could keep a "volatile" flag in the - * inode to indicate which ones to keep. - */ -static void -proc_delete_dentry(struct dentry * dentry) -{ - d_drop(dentry); -} - -struct dentry_operations proc_dentry_operations = -{ - NULL, /* revalidate */ - NULL, /* d_hash */ - NULL, /* d_compare */ - proc_delete_dentry /* d_delete(struct dentry *) */ -}; - -/* - * Don't create negative dentries here, return -ENOENT by hand - * instead. - */ -struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry) -{ - struct inode *inode; - struct proc_dir_entry * de; - int error; - - error = -ENOENT; - inode = NULL; - de = (struct proc_dir_entry *) dir->u.generic_ip; - if (de) { - for (de = de->subdir; de ; de = de->next) { - if (!de || !de->low_ino) - continue; - if (de->namelen != dentry->d_name.len) - continue; - if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { - int ino = de->low_ino; - error = -EINVAL; - inode = proc_get_inode(dir->i_sb, ino, de); - break; - } - } - } - - if (inode) { - dentry->d_op = &proc_dentry_operations; - d_add(dentry, inode); - return NULL; - } - return ERR_PTR(error); + proc_bus = proc_mkdir("bus", 0); } static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry) @@ -564,63 +125,6 @@ static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentr return proc_pid_lookup(dir, dentry); } -/* - * This returns non-zero if at EOF, so that the /proc - * root directory can use this and check if it should - * continue with the <pid> entries.. - * - * Note that the VFS-layer doesn't care about the return - * value of the readdir() call, as long as it's non-negative - * for success.. - */ -int proc_readdir(struct file * filp, - void * dirent, filldir_t filldir) -{ - struct proc_dir_entry * de; - unsigned int ino; - int i; - struct inode *inode = filp->f_dentry->d_inode; - - ino = inode->i_ino; - de = (struct proc_dir_entry *) inode->u.generic_ip; - if (!de) - return -EINVAL; - i = filp->f_pos; - switch (i) { - case 0: - if (filldir(dirent, ".", 1, i, ino) < 0) - return 0; - i++; - filp->f_pos++; - /* fall through */ - case 1: - if (filldir(dirent, "..", 2, i, de->parent->low_ino) < 0) - return 0; - i++; - filp->f_pos++; - /* fall through */ - default: - de = de->subdir; - i -= 2; - for (;;) { - if (!de) - return 1; - if (!i) - break; - de = de->next; - i--; - } - - do { - if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino) < 0) - return 0; - filp->f_pos++; - de = de->next; - } while (de); - } - return 1; -} - static int proc_root_readdir(struct file * filp, void * dirent, filldir_t filldir) { @@ -636,14 +140,35 @@ static int proc_root_readdir(struct file * filp, return proc_pid_readdir(filp, dirent, filldir); } -static int proc_unlink(struct inode *dir, struct dentry *dentry) -{ - struct proc_dir_entry * dp = dir->u.generic_ip; +/* + * The root /proc directory is special, as it has the + * <pid> directories. Thus we don't use the generic + * directory handling functions for that.. + */ +static struct file_operations proc_root_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + proc_root_readdir, /* readdir */ +}; -printk("proc_file_unlink: deleting %s/%s\n", dp->name, dentry->d_name.name); +/* + * proc root can do almost nothing.. + */ +static struct inode_operations proc_root_inode_operations = { + &proc_root_operations, /* default base directory file-ops */ + NULL, /* create */ + proc_root_lookup, /* lookup */ +}; - remove_proc_entry(dentry->d_name.name, dp); - dentry->d_inode->i_nlink = 0; - d_delete(dentry); - return 0; -} +/* + * This is the root "inode" in the /proc tree.. + */ +struct proc_dir_entry proc_root = { + PROC_ROOT_INO, 5, "/proc", + S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, + 0, &proc_root_inode_operations, + NULL, NULL, + NULL, + &proc_root, NULL +}; |