]> git.hungrycats.org Git - linux/commitdiff
[PATCH] (3/5) sane procfs/dcache interaction
authorAlexander Viro <viro@math.psu.edu>
Mon, 22 Apr 2002 06:03:37 +0000 (23:03 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Mon, 22 Apr 2002 06:03:37 +0000 (23:03 -0700)
 - 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.

fs/proc/base.c
include/linux/sched.h
kernel/exit.c
kernel/fork.c

index 44c1189b6eed3583b297d8cfa4810bff7e808ff1..7dfa4f269ab642fb79750d4de44d7b259c9c9ace 100644 (file)
@@ -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);
index 8f0df64bb7231b0ae32bfbb66ec574a9d3a18c4d..a65b376d99daa1fcdcca2a81ba016ea763cb7011 100644 (file)
@@ -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);
index 58b05e3ef9f8294852c81e4908f030d6f076403e..e3fdd078f449bd2dd79b5f52ce62de9b76694a9d 100644 (file)
@@ -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)
index d7a274cbec950e80ea025388eb588692f4f9c0ca..380c1bafe75ce292e3977b7f00d336a06321f075 100644 (file)
@@ -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);