aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@openvz.org>2007-10-19 02:40:03 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-19 14:53:38 -0400
commit60347f6716aa49831ac311e04d77ccdc50dc024a (patch)
tree82e666fef22f43550da42ad368a61a5e9a59ef96
parent8bf9725c29f2589237dd696d06a204230add0ba3 (diff)
pid namespaces: prepare proc_flust_task() to flush entries from multiple proc trees
The first part is trivial - we just make the proc_flush_task() to operate on arbitrary vfsmount with arbitrary ids and pass the pid and global proc_mnt to it. The other change is more tricky: I moved the proc_flush_task() call in release_task() higher to address the following problem. When flushing task from many proc trees we need to know the set of ids (not just one pid) to find the dentries' names to flush. Thus we need to pass the task's pid to proc_flush_task() as struct pid is the only object that can provide all the pid numbers. But after __exit_signal() task has detached all his pids and this information is lost. This creates a tiny gap for proc_pid_lookup() to bring some dentries back to tree and keep them in hash (since pids are still alive before __exit_signal()) till the next shrink, but since proc_flush_task() does not provide a 100% guarantee that the dentries will be flushed, this is OK to do so. Signed-off-by: Pavel Emelyanov <xemul@openvz.org> Cc: Oleg Nesterov <oleg@tv-sign.ru> Cc: Sukadev Bhattiprolu <sukadev@us.ibm.com> Cc: Paul Menage <menage@google.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/proc/base.c27
-rw-r--r--include/linux/proc_fs.h4
-rw-r--r--kernel/exit.c2
3 files changed, 24 insertions, 9 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 6afca09a6534..36983e7bb2c1 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -74,6 +74,7 @@
74#include <linux/nsproxy.h> 74#include <linux/nsproxy.h>
75#include <linux/oom.h> 75#include <linux/oom.h>
76#include <linux/elf.h> 76#include <linux/elf.h>
77#include <linux/pid_namespace.h>
77#include "internal.h" 78#include "internal.h"
78 79
79/* NOTE: 80/* NOTE:
@@ -2204,27 +2205,27 @@ static const struct inode_operations proc_tgid_base_inode_operations = {
2204 * that no dcache entries will exist at process exit time it 2205 * that no dcache entries will exist at process exit time it
2205 * just makes it very unlikely that any will persist. 2206 * just makes it very unlikely that any will persist.
2206 */ 2207 */
2207void proc_flush_task(struct task_struct *task) 2208static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
2208{ 2209{
2209 struct dentry *dentry, *leader, *dir; 2210 struct dentry *dentry, *leader, *dir;
2210 char buf[PROC_NUMBUF]; 2211 char buf[PROC_NUMBUF];
2211 struct qstr name; 2212 struct qstr name;
2212 2213
2213 name.name = buf; 2214 name.name = buf;
2214 name.len = snprintf(buf, sizeof(buf), "%d", task->pid); 2215 name.len = snprintf(buf, sizeof(buf), "%d", pid);
2215 dentry = d_hash_and_lookup(proc_mnt->mnt_root, &name); 2216 dentry = d_hash_and_lookup(mnt->mnt_root, &name);
2216 if (dentry) { 2217 if (dentry) {
2217 shrink_dcache_parent(dentry); 2218 shrink_dcache_parent(dentry);
2218 d_drop(dentry); 2219 d_drop(dentry);
2219 dput(dentry); 2220 dput(dentry);
2220 } 2221 }
2221 2222
2222 if (thread_group_leader(task)) 2223 if (tgid == 0)
2223 goto out; 2224 goto out;
2224 2225
2225 name.name = buf; 2226 name.name = buf;
2226 name.len = snprintf(buf, sizeof(buf), "%d", task->tgid); 2227 name.len = snprintf(buf, sizeof(buf), "%d", tgid);
2227 leader = d_hash_and_lookup(proc_mnt->mnt_root, &name); 2228 leader = d_hash_and_lookup(mnt->mnt_root, &name);
2228 if (!leader) 2229 if (!leader)
2229 goto out; 2230 goto out;
2230 2231
@@ -2235,7 +2236,7 @@ void proc_flush_task(struct task_struct *task)
2235 goto out_put_leader; 2236 goto out_put_leader;
2236 2237
2237 name.name = buf; 2238 name.name = buf;
2238 name.len = snprintf(buf, sizeof(buf), "%d", task->pid); 2239 name.len = snprintf(buf, sizeof(buf), "%d", pid);
2239 dentry = d_hash_and_lookup(dir, &name); 2240 dentry = d_hash_and_lookup(dir, &name);
2240 if (dentry) { 2241 if (dentry) {
2241 shrink_dcache_parent(dentry); 2242 shrink_dcache_parent(dentry);
@@ -2250,6 +2251,18 @@ out:
2250 return; 2251 return;
2251} 2252}
2252 2253
2254/*
2255 * when flushing dentries from proc one need to flush them from global
2256 * proc (proc_mnt) and from all the namespaces' procs this task was seen
2257 * in. this call is supposed to make all this job.
2258 */
2259
2260void proc_flush_task(struct task_struct *task)
2261{
2262 proc_flush_task_mnt(proc_mnt, task->pid,
2263 thread_group_leader(task) ? 0 : task->tgid);
2264}
2265
2253static struct dentry *proc_pid_instantiate(struct inode *dir, 2266static struct dentry *proc_pid_instantiate(struct inode *dir,
2254 struct dentry * dentry, 2267 struct dentry * dentry,
2255 struct task_struct *task, const void *ptr) 2268 struct task_struct *task, const void *ptr)
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 20741f668f7b..dbd601c7244c 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -207,7 +207,9 @@ extern void proc_net_remove(struct net *net, const char *name);
207#define proc_net_create(net, name, mode, info) ({ (void)(mode), NULL; }) 207#define proc_net_create(net, name, mode, info) ({ (void)(mode), NULL; })
208static inline void proc_net_remove(struct net *net, const char *name) {} 208static inline void proc_net_remove(struct net *net, const char *name) {}
209 209
210static inline void proc_flush_task(struct task_struct *task) { } 210static inline void proc_flush_task(struct task_struct *task)
211{
212}
211 213
212static inline struct proc_dir_entry *create_proc_entry(const char *name, 214static inline struct proc_dir_entry *create_proc_entry(const char *name,
213 mode_t mode, struct proc_dir_entry *parent) { return NULL; } 215 mode_t mode, struct proc_dir_entry *parent) { return NULL; }
diff --git a/kernel/exit.c b/kernel/exit.c
index df2eee9c68ce..d9e8e5ee9d7f 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -148,6 +148,7 @@ void release_task(struct task_struct * p)
148 int zap_leader; 148 int zap_leader;
149repeat: 149repeat:
150 atomic_dec(&p->user->processes); 150 atomic_dec(&p->user->processes);
151 proc_flush_task(p);
151 write_lock_irq(&tasklist_lock); 152 write_lock_irq(&tasklist_lock);
152 ptrace_unlink(p); 153 ptrace_unlink(p);
153 BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children)); 154 BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children));
@@ -175,7 +176,6 @@ repeat:
175 } 176 }
176 177
177 write_unlock_irq(&tasklist_lock); 178 write_unlock_irq(&tasklist_lock);
178 proc_flush_task(p);
179 release_thread(p); 179 release_thread(p);
180 call_rcu(&p->rcu, delayed_put_task_struct); 180 call_rcu(&p->rcu, delayed_put_task_struct);
181 181