<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
From: Manfred Spraul &lt;manfred@colorfullife.com&gt;

Fixes a race between proc_pid_lookup and sys_exit.

- The inodes and dentries for /proc/&lt;pid&gt;/whatever are cached in the dentry
  cache.  d_revalidate is used to protect against stale data: d_revalidate
  returns invalid if the task exited.

  Additionally, sys_exit flushes the dentries for the task that died -
  otherwise the dentries would stay around until they arrive at the end of
  the LRU, which could take some time.  But there is one race:

  - proc_pid_lookup finds a task and prepares new dentries for it. It must 
    drop all locks for that operation.
  - the process exits, and the /proc/ dentries are flushed. Nothing 
    happens, because they are not yet in the hash tables.
  - proc_pid_lookup adds the task to the dentry cache.

  Result: dentry of a dead task in the hash tables.

  The patch fixes that problem by flushing again if proc_pid_lookup notices
  that the thread exited while it created the dentry.  The patch should go
  in, but it's not critical.


- task-&gt;proc_dentry must be the dentry of /proc/&lt;pid&gt;.  That way sys_exit
  can flush the whole subtree at exit time.  proc_task_lookup is a direct
  copy of proc_pid_lookup and handles /proc/&lt;&gt;/task/&lt;pid&gt;.  It contains the
  lines that set task-&gt;proc_dentry.  This is bogus, and must be removed.  

  This hunk is much more critical, because creates a de-facto dentry leak
  (they are recovered after flushing real dentries from the cache).



 fs/proc/base.c |   15 +++++++++++----
 1 files changed, 11 insertions(+), 4 deletions(-)

diff -puN fs/proc/base.c~proc_pid_lookup-vs-exit-race-fix fs/proc/base.c
--- 25/fs/proc/base.c~proc_pid_lookup-vs-exit-race-fix	2003-11-19 10:43:11.000000000 -0800
+++ 25-akpm/fs/proc/base.c	2003-11-19 10:43:11.000000000 -0800
@@ -1524,6 +1524,7 @@ struct dentry *proc_pid_lookup(struct in
 	struct inode *inode;
 	struct proc_inode *ei;
 	unsigned tgid;
+	int died;
 
 	if (dentry-&gt;d_name.len == 4 &amp;&amp; !memcmp(dentry-&gt;d_name.name,"self",4)) {
 		inode = new_inode(dir-&gt;i_sb);
@@ -1567,12 +1568,21 @@ struct dentry *proc_pid_lookup(struct in
 
 	dentry-&gt;d_op = &amp;pid_base_dentry_operations;
 
+	died = 0;
+	d_add(dentry, inode);
 	spin_lock(&amp;task-&gt;proc_lock);
 	task-&gt;proc_dentry = dentry;
-	d_add(dentry, inode);
+	if (!pid_alive(task)) {
+		dentry = proc_pid_unhash(task);
+		died = 1;
+	}
 	spin_unlock(&amp;task-&gt;proc_lock);
 
 	put_task_struct(task);
+	if (died) {
+		proc_pid_flush(dentry);
+		goto out;
+	}
 	return NULL;
 out:
 	return ERR_PTR(-ENOENT);
@@ -1612,10 +1622,7 @@ static struct dentry *proc_task_lookup(s
 
 	dentry-&gt;d_op = &amp;pid_base_dentry_operations;
 
-	spin_lock(&amp;task-&gt;proc_lock);
-	task-&gt;proc_dentry = dentry;
 	d_add(dentry, inode);
-	spin_unlock(&amp;task-&gt;proc_lock);
 
 	put_task_struct(task);
 	return NULL;

_
</pre></body></html>