Commit 00306333 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] (3/5) sane procfs/dcache interaction

 - sane dentry retention.  Namely, we don't kill /proc/<pid> dentries at the
   first opportunity (as the current tree does).  Instead we do the following:
	* ->d_delete() kills it only if process is already dead.
	* all ->lookup() in proc/base.c end with checking if process is still
	  alive and unhash if it isn't.
	* proc_pid_lookup() (lookup for /proc/<pid>) caches reference to dentry
	  in task_struct.  It's _not_ counted in ->d_count.
	* ->d_iput() resets said reference to NULL.
	* release_task() (burying a zombie) checks if there is a cached
	  reference and if there is - shrinks the subtree.
	* tasklist_lock is used for exclusion.
   That way we are guaranteed that after release_task() all dentries in
   /proc/<pid> will go away as soon as possible; OTOH, before release_task()
   we have normal retention policy - they go away under memory pressure with
   the same rules as for dentries on any other fs.
parent 981936da
......@@ -747,7 +747,7 @@ static int pid_fd_revalidate(struct dentry * dentry, int flags)
* directory. In this case, however, we can do it - no aliasing problems
* due to the way we treat inodes.
*/
static int pid_base_revalidate(struct dentry * dentry, int flags)
static int pid_revalidate(struct dentry * dentry, int flags)
{
if (proc_task(dentry->d_inode)->pid)
return 1;
......@@ -755,25 +755,42 @@ static int pid_base_revalidate(struct dentry * dentry, int flags)
return 0;
}
static int pid_delete_dentry(struct dentry * dentry)
static void pid_base_iput(struct dentry *dentry, struct inode *inode)
{
struct task_struct *task = proc_task(inode);
write_lock_irq(&tasklist_lock);
if (task->proc_dentry == dentry)
task->proc_dentry = NULL;
write_unlock_irq(&tasklist_lock);
iput(inode);
}
static int pid_fd_delete_dentry(struct dentry * dentry)
{
return 1;
}
static int pid_delete_dentry(struct dentry * dentry)
{
return proc_task(dentry->d_inode)->pid == 0;
}
static struct dentry_operations pid_fd_dentry_operations =
{
d_revalidate: pid_fd_revalidate,
d_delete: pid_delete_dentry,
d_delete: pid_fd_delete_dentry,
};
static struct dentry_operations pid_dentry_operations =
{
d_revalidate: pid_revalidate,
d_delete: pid_delete_dentry,
};
static struct dentry_operations pid_base_dentry_operations =
{
d_revalidate: pid_base_revalidate,
d_revalidate: pid_revalidate,
d_iput: pid_base_iput,
d_delete: pid_delete_dentry,
};
......@@ -842,6 +859,8 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry)
inode->i_mode |= S_IWUSR | S_IXUSR;
dentry->d_op = &pid_fd_dentry_operations;
d_add(dentry, inode);
if (!proc_task(dentry->d_inode)->pid)
d_drop(dentry);
return NULL;
out_unlock2:
......@@ -959,6 +978,8 @@ static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
}
dentry->d_op = &pid_dentry_operations;
d_add(dentry, inode);
if (!proc_task(dentry->d_inode)->pid)
d_drop(dentry);
return NULL;
out:
......@@ -1045,6 +1066,11 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry)
dentry->d_op = &pid_base_dentry_operations;
d_add(dentry, inode);
read_lock(&tasklist_lock);
proc_task(dentry->d_inode)->proc_dentry = dentry;
read_unlock(&tasklist_lock);
if (!proc_task(dentry->d_inode)->pid)
d_drop(dentry);
return NULL;
out:
return ERR_PTR(-ENOENT);
......
......@@ -346,6 +346,7 @@ struct task_struct {
/* journalling filesystem info */
void *journal_info;
struct dentry *proc_dentry;
};
extern void __put_task_struct(struct task_struct *tsk);
......
......@@ -29,13 +29,28 @@ int getrusage(struct task_struct *, int, struct rusage *);
static inline void __unhash_process(struct task_struct *p)
{
struct dentry *proc_dentry;
write_lock_irq(&tasklist_lock);
nr_threads--;
unhash_pid(p);
REMOVE_LINKS(p);
list_del(&p->thread_group);
p->pid = 0;
proc_dentry = p->proc_dentry;
if (unlikely(proc_dentry)) {
spin_lock(&dcache_lock);
if (!list_empty(&proc_dentry->d_hash)) {
dget_locked(proc_dentry);
list_del_init(&proc_dentry->d_hash);
} else
proc_dentry = NULL;
spin_unlock(&dcache_lock);
}
write_unlock_irq(&tasklist_lock);
if (unlikely(proc_dentry)) {
shrink_dcache_parent(proc_dentry);
dput(proc_dentry);
}
}
static void release_task(struct task_struct * p)
......
......@@ -665,6 +665,7 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
copy_flags(clone_flags, p);
p->pid = get_pid(clone_flags);
p->proc_dentry = NULL;
INIT_LIST_HEAD(&p->run_list);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment