diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-05-12 21:05:59 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-05-12 21:05:59 +0000 |
commit | ba2dacab305c598cd4c34a604f8e276bf5bab5ff (patch) | |
tree | 78670a0139bf4d5ace617b29b7eba82bbc74d602 /fs/proc | |
parent | b77bf69998121e689c5e86cc5630d39a0a9ee6ca (diff) |
Merge with Linux 2.3.99-pre7 and various other bits.
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/array.c | 69 | ||||
-rw-r--r-- | fs/proc/base.c | 144 | ||||
-rw-r--r-- | fs/proc/generic.c | 46 | ||||
-rw-r--r-- | fs/proc/inode.c | 16 | ||||
-rw-r--r-- | fs/proc/procfs_syms.c | 12 | ||||
-rw-r--r-- | fs/proc/root.c | 30 |
6 files changed, 175 insertions, 142 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index 6feabd36d..57746b03e 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -148,20 +148,25 @@ static inline char * task_state(struct task_struct *p, char *buffer) { int g; + read_lock(&tasklist_lock); buffer += sprintf(buffer, "State:\t%s\n" "Pid:\t%d\n" "PPid:\t%d\n" "TracerPid:\t%d\n" "Uid:\t%d\t%d\t%d\t%d\n" - "Gid:\t%d\t%d\t%d\t%d\n" - "FDSize:\t%d\n" - "Groups:\t", + "Gid:\t%d\t%d\t%d\t%d\n", get_task_state(p), p->pid, p->p_opptr->pid, p->p_pptr->pid != p->p_opptr->pid ? p->p_opptr->pid : 0, p->uid, p->euid, p->suid, p->fsuid, - p->gid, p->egid, p->sgid, p->fsgid, + p->gid, p->egid, p->sgid, p->fsgid); + read_unlock(&tasklist_lock); + task_lock(p); + buffer += sprintf(buffer, + "FDSize:\t%d\n" + "Groups:\t", p->files ? p->files->max_fds : 0); + task_unlock(p); for (g = 0; g < p->ngroups; g++) buffer += sprintf(buffer, "%d ", p->groups[g]); @@ -264,20 +269,25 @@ extern inline char *task_cap(struct task_struct *p, char *buffer) } -/* task is locked, so we are safe here */ - int proc_pid_status(struct task_struct *task, char * buffer) { char * orig = buffer; - struct mm_struct *mm = task->mm; + struct mm_struct *mm; #if defined(CONFIG_ARCH_S390) int line,len; #endif buffer = task_name(task, buffer); buffer = task_state(task, buffer); - if (mm) + task_lock(task); + mm = task->mm; + if(mm) + atomic_inc(&mm->mm_users); + task_unlock(task); + if (mm) { buffer = task_mem(mm, buffer); + mmput(mm); + } buffer = task_sig(task, buffer); buffer = task_cap(task, buffer); #if defined(CONFIG_ARCH_S390) @@ -287,20 +297,25 @@ int proc_pid_status(struct task_struct *task, char * buffer) return buffer - orig; } -/* task is locked, so we are safe here */ - int proc_pid_stat(struct task_struct *task, char * buffer) { - struct mm_struct *mm = task->mm; unsigned long vsize, eip, esp, wchan; long priority, nice; int tty_pgrp; sigset_t sigign, sigcatch; char state; int res; + pid_t ppid; + int tty_nr; + struct mm_struct *mm; state = *get_task_state(task); vsize = eip = esp = 0; + task_lock(task); + mm = task->mm; + if(mm) + atomic_inc(&mm->mm_users); + task_unlock(task); if (mm) { struct vm_area_struct *vma; down(&mm->mmap_sem); @@ -318,10 +333,13 @@ int proc_pid_stat(struct task_struct *task, char * buffer) collect_sigign_sigcatch(task, &sigign, &sigcatch); + task_lock(task); if (task->tty) tty_pgrp = task->tty->pgrp; else tty_pgrp = -1; + tty_nr = task->tty ? kdev_t_to_nr(task->tty->device) : 0; + task_unlock(task); /* scale priority and nice values from timeslices to -20..20 */ /* to make it look like a "normal" Unix priority/nice value */ @@ -330,16 +348,19 @@ int proc_pid_stat(struct task_struct *task, char * buffer) nice = task->priority; nice = 20 - (nice * 20 + DEF_PRIORITY / 2) / DEF_PRIORITY; + read_lock(&tasklist_lock); + ppid = task->p_opptr->pid; + read_unlock(&tasklist_lock); 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", task->pid, task->comm, state, - task->p_opptr->pid, + ppid, task->pgrp, task->session, - task->tty ? kdev_t_to_nr(task->tty->device) : 0, + tty_nr, tty_pgrp, task->flags, task->min_flt, @@ -376,6 +397,8 @@ int proc_pid_stat(struct task_struct *task, char * buffer) task->cnswap, task->exit_signal, task->processor); + if(mm) + mmput(mm); return res; } @@ -455,9 +478,14 @@ static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long en int proc_pid_statm(struct task_struct *task, char * buffer) { - struct mm_struct *mm = task->mm; + struct mm_struct *mm; int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0; + task_lock(task); + mm = task->mm; + if(mm) + atomic_inc(&mm->mm_users); + task_unlock(task); if (mm) { struct vm_area_struct * vma; down(&mm->mmap_sem); @@ -482,6 +510,7 @@ int proc_pid_statm(struct task_struct *task, 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); @@ -523,7 +552,7 @@ int proc_pid_statm(struct task_struct *task, char * buffer) ssize_t proc_pid_read_maps (struct task_struct *task, struct file * file, char * buf, size_t count, loff_t *ppos) { - struct mm_struct *mm = task->mm; + struct mm_struct *mm; struct vm_area_struct * map, * next; char * destptr = buf, * buffer; loff_t lineno; @@ -539,7 +568,14 @@ ssize_t proc_pid_read_maps (struct task_struct *task, struct file * file, char * if (!buffer) goto out; - if (!mm || count == 0) + if (count == 0) + goto getlen_out; + task_lock(task); + mm = task->mm; + if (mm) + atomic_inc(&mm->mm_users); + task_unlock(task); + if (!mm) goto getlen_out; /* Check whether the mmaps could change if we sleep */ @@ -637,6 +673,7 @@ ssize_t proc_pid_read_maps (struct task_struct *task, struct file * file, char * /* encode f_pos */ *ppos = (lineno << MAPS_LINE_SHIFT) + column; + mmput(mm); getlen_out: retval = destptr - buf; diff --git a/fs/proc/base.c b/fs/proc/base.c index ae3c36122..2e83c6a4e 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -40,12 +40,18 @@ int proc_pid_statm(struct task_struct*,char*); int proc_pid_cpu(struct task_struct*,char*); /* MOUNT_REWRITE: make all files have non-NULL ->f_vfsmnt (pipefs, sockfs) */ +/* Until then... */ +#define NULL_VFSMNT /* remove as soon as pipefs and sockfs will be there */ + static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) { if (inode->u.proc_i.file) { - if (inode->u.proc_i.file->f_vfsmnt) { - *mnt = mntget(inode->u.proc_i.file->f_vfsmnt); - } +#ifdef NULL_VFSMNT + if (!inode->u.proc_i.file->f_vfsmnt) + mntget(*mnt); + else +#endif + *mnt = mntget(inode->u.proc_i.file->f_vfsmnt); *dentry = dget(inode->u.proc_i.file->f_dentry); return 0; } @@ -59,9 +65,11 @@ static int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfs int result = -ENOENT; struct task_struct *task = inode->u.proc_i.task; - if (!task_lock(task)) - return result; + task_lock(task); mm = task->mm; + if (mm) + atomic_inc(&mm->mm_users); + task_unlock(task); if (!mm) goto out; down(&mm->mmap_sem); @@ -77,67 +85,81 @@ static int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfs vma = vma->vm_next; } up(&mm->mmap_sem); + mmput(mm); out: - task_unlock(task); return result; } static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) { + struct fs_struct *fs; int result = -ENOENT; - if (task_lock(inode->u.proc_i.task)) { - struct fs_struct *fs = inode->u.proc_i.task->fs; - if (fs) { - *mnt = mntget(fs->pwdmnt); - *dentry = dget(fs->pwd); - result = 0; - } - task_unlock(inode->u.proc_i.task); + task_lock(inode->u.proc_i.task); + fs = inode->u.proc_i.task->fs; + if(fs) + atomic_inc(&fs->count); + task_unlock(inode->u.proc_i.task); + if (fs) { + *mnt = mntget(fs->pwdmnt); + *dentry = dget(fs->pwd); + result = 0; + put_fs_struct(fs); } return result; } static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) { + struct fs_struct *fs; int result = -ENOENT; - if (task_lock(inode->u.proc_i.task)) { - struct fs_struct *fs = inode->u.proc_i.task->fs; - if (fs) { - *mnt = mntget(fs->rootmnt); - *dentry = dget(fs->root); - result = 0; - } - task_unlock(inode->u.proc_i.task); + task_lock(inode->u.proc_i.task); + fs = inode->u.proc_i.task->fs; + if(fs) + atomic_inc(&fs->count); + task_unlock(inode->u.proc_i.task); + if (fs) { + *mnt = mntget(fs->rootmnt); + *dentry = dget(fs->root); + result = 0; + put_fs_struct(fs); } 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; + struct mm_struct *mm; int res = 0; + task_lock(task); + mm = task->mm; + if (mm) + atomic_inc(&mm->mm_users); + task_unlock(task); 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); + mmput(mm); } 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; + struct mm_struct *mm; int res = 0; + task_lock(task); + mm = task->mm; + if (mm) + atomic_inc(&mm->mm_users); + task_unlock(task); 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); + mmput(mm); } return res; } @@ -174,7 +196,6 @@ static int standard_permission(struct inode *inode, int mask) static int proc_permission(struct inode *inode, int mask) { struct dentry *de, *base, *root; - struct super_block *our_sb, *sb, *below; struct vfsmount *our_vfsmnt, *vfsmnt, *mnt; if (standard_permission(inode, mask) != 0) @@ -187,14 +208,12 @@ static int proc_permission(struct inode *inode, int mask) de = root; mnt = vfsmnt; - 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) + + while (vfsmnt != our_vfsmnt) { + if (vfsmnt == vfsmnt->mnt_parent) goto out; - sb = below; + de = vfsmnt->mnt_mountpoint; + vfsmnt = vfsmnt->mnt_parent; } if (!is_subdir(de, base)) @@ -216,10 +235,7 @@ static ssize_t pid_maps_read(struct file * file, char * buf, 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; } @@ -243,15 +259,8 @@ static ssize_t proc_info_read(struct file * file, char * buf, 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; @@ -368,10 +377,12 @@ static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) { struct inode *inode = dentry->d_inode; int error; +#ifdef NULL_VFSMNT + struct vfsmount *dummy = mntget(nd->mnt); +#endif /* We don't need a base pointer in the /proc filesystem */ - dput(nd->dentry); - mntput(nd->mnt); + path_release(nd); error = proc_permission(inode, MAY_EXEC); if (error) @@ -379,6 +390,9 @@ static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) error = inode->u.proc_i.op.proc_get_link(inode, &nd->dentry, &nd->mnt); out: +#ifdef NULL_VFSMNT + mntput(dummy); +#endif return error; } @@ -421,18 +435,19 @@ static int proc_pid_readlink(struct dentry * dentry, char * buffer, int buflen) { int error; struct inode *inode = dentry->d_inode; - struct vfsmount *mnt; + struct dentry *de; + struct vfsmount *mnt = NULL; error = proc_permission(inode, MAY_EXEC); if (error) goto out; - error = inode->u.proc_i.op.proc_get_link(inode, &dentry, &mnt); + error = inode->u.proc_i.op.proc_get_link(inode, &de, &mnt); if (error) goto out; - error = do_proc_readlink(dentry, mnt, buffer, buflen); - dput(dentry); + error = do_proc_readlink(de, mnt, buffer, buflen); + dput(de); mntput(mnt); out: return error; @@ -496,6 +511,7 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) unsigned int fd, pid, ino; int retval; char buf[NUMBUF]; + struct files_struct * files; retval = 0; pid = p->pid; @@ -512,12 +528,19 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) goto out; filp->f_pos++; default: + task_lock(p); + files = p->files; + if (files) + atomic_inc(&files->count); + task_unlock(p); + if (!files) + goto out; for (fd = filp->f_pos-2; - p->p_pptr && p->files && fd < p->files->max_fds; + fd < files->max_fds; fd++, filp->f_pos++) { unsigned int i,j; - if (!fcheck_task(p, fd)) + if (!fcheck_files(files, fd)) continue; j = NUMBUF; @@ -531,8 +554,8 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) ino = fake_ino(pid, PROC_PID_FD_DIR + fd); if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino) < 0) break; - } + put_files_struct(files); } out: return retval; @@ -688,16 +711,20 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry) inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_FD_DIR+fd); if (!inode) goto out; - /* FIXME */ + task_lock(task); files = task->files; - if (!files) /* can we ever get here if that's the case? */ + if (files) + atomic_inc(&files->count); + task_unlock(task); + if (!files) goto out_unlock; read_lock(&files->file_lock); - file = inode->u.proc_i.file = fcheck_task(task, fd); + file = inode->u.proc_i.file = fcheck_files(files, fd); if (!file) goto out_unlock2; get_file(file); read_unlock(&files->file_lock); + put_files_struct(files); inode->i_op = &proc_pid_link_inode_operations; inode->i_size = 64; inode->i_mode = S_IFLNK; @@ -711,6 +738,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry) return NULL; out_unlock2: + put_files_struct(files); read_unlock(&files->file_lock); out_unlock: iput(inode); diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 4d6662780..31e43fab9 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -373,36 +373,30 @@ int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) static void proc_kill_inodes(struct proc_dir_entry *de) { struct list_head *p; - struct super_block *sb; + struct super_block *sb = proc_mnt->mnt_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. + * Actually it's a partial revoke(). */ - 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(); + 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, diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 90ed410b7..67273b3ba 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -82,18 +82,7 @@ static void proc_delete_inode(struct inode *inode) } } -struct super_block *proc_super_blocks = NULL; - -static void proc_put_super(struct super_block *sb) -{ - struct super_block **p = &proc_super_blocks; - while (*p != sb) { - if (!*p) /* should never happen */ - return; - p = (struct super_block **)&(*p)->u.generic_sbp; - } - *p = (struct super_block *)(*p)->u.generic_sbp; -} +struct vfsmount *proc_mnt; static void proc_read_inode(struct inode * inode) { @@ -115,7 +104,6 @@ static struct super_operations proc_sops = { read_inode: proc_read_inode, put_inode: proc_put_inode, delete_inode: proc_delete_inode, - put_super: proc_put_super, statfs: proc_statfs, }; @@ -222,8 +210,6 @@ struct super_block *proc_read_super(struct super_block *s,void *data, if (!s->s_root) goto out_no_root; parse_options(data, &root_inode->i_uid, &root_inode->i_gid); - s->u.generic_sbp = (void*) proc_super_blocks; - proc_super_blocks = s; return s; out_no_root: diff --git a/fs/proc/procfs_syms.c b/fs/proc/procfs_syms.c index 097e83468..e6d1cf74c 100644 --- a/fs/proc/procfs_syms.c +++ b/fs/proc/procfs_syms.c @@ -20,16 +20,24 @@ EXPORT_SYMBOL(proc_net); EXPORT_SYMBOL(proc_bus); EXPORT_SYMBOL(proc_root_driver); -static DECLARE_FSTYPE(proc_fs_type, "proc", proc_read_super, 0); +static DECLARE_FSTYPE(proc_fs_type, "proc", proc_read_super, FS_SINGLE); static int __init init_proc_fs(void) { - return register_filesystem(&proc_fs_type); + int err = register_filesystem(&proc_fs_type); + if (!err) { + proc_mnt = kern_mount(&proc_fs_type); + err = PTR_ERR(proc_mnt); + if (!IS_ERR(proc_mnt)) + err = 0; + } + return err; } static void __exit exit_proc_fs(void) { unregister_filesystem(&proc_fs_type); + kern_umount(proc_mnt); } module_init(init_proc_fs) diff --git a/fs/proc/root.c b/fs/proc/root.c index af01f0281..8088d064d 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -76,32 +76,12 @@ void __init proc_root_init(void) static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry) { - struct task_struct *p; - if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */ - extern unsigned long total_forks; - static int last_timestamp = 0; - - /* - * this one can be a serious 'ps' performance problem if - * there are many threads running - thus we do 'lazy' - * link-recalculation - we change it only if the number - * of threads has increased. - */ - if (total_forks != last_timestamp) { - int nlink = proc_root.nlink; - - read_lock(&tasklist_lock); - last_timestamp = total_forks; - for_each_task(p) - nlink++; - read_unlock(&tasklist_lock); - /* - * subtract the # of idle threads which - * do not show up in /proc: - */ - dir->i_nlink = nlink - smp_num_cpus; - } + int nlink = proc_root.nlink; + + nlink += nr_threads; + + dir->i_nlink = nlink; } if (!proc_lookup(dir, dentry)) |