summaryrefslogtreecommitdiffstats
path: root/fs/proc
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-05-12 21:05:59 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-05-12 21:05:59 +0000
commitba2dacab305c598cd4c34a604f8e276bf5bab5ff (patch)
tree78670a0139bf4d5ace617b29b7eba82bbc74d602 /fs/proc
parentb77bf69998121e689c5e86cc5630d39a0a9ee6ca (diff)
Merge with Linux 2.3.99-pre7 and various other bits.
Diffstat (limited to 'fs/proc')
-rw-r--r--fs/proc/array.c69
-rw-r--r--fs/proc/base.c144
-rw-r--r--fs/proc/generic.c46
-rw-r--r--fs/proc/inode.c16
-rw-r--r--fs/proc/procfs_syms.c12
-rw-r--r--fs/proc/root.c30
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))