aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/fork.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2006-03-31 05:31:42 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-31 15:19:00 -0500
commit92476d7fc0326a409ab1d3864a04093a6be9aca7 (patch)
treeea50a5a31522492d9915e0763a7adc6ac87c4fbc /kernel/fork.c
parent8c7904a00b06d2ee51149794b619e07369fcf9d4 (diff)
[PATCH] pidhash: Refactor the pid hash table
Simplifies the code, reduces the need for 4 pid hash tables, and makes the code more capable. In the discussions I had with Oleg it was felt that to a large extent the cleanup itself justified the work. With struct pid being dynamically allocated meant we could create the hash table entry when the pid was allocated and free the hash table entry when the pid was freed. Instead of playing with the hash lists when ever a process would attach or detach to a process. For myself the fact that it gave what my previous task_ref patch gave for free with simpler code was a big win. The problem is that if you hold a reference to struct task_struct you lock in 10K of low memory. If you do that in a user controllable way like /proc does, with an unprivileged but hostile user space application with typical resource limits of 1000 fds and 100 processes I can trigger the OOM killer by consuming all of low memory with task structs, on a machine wight 1GB of low memory. If I instead hold a reference to struct pid which holds a pointer to my task_struct, I don't suffer from that problem because struct pid is 2 orders of magnitude smaller. In fact struct pid is small enough that most other kernel data structures dwarf it, so simply limiting the number of referring data structures is enough to prevent exhaustion of low memory. This splits the current struct pid into two structures, struct pid and struct pid_link, and reduces our number of hash tables from PIDTYPE_MAX to just one. struct pid_link is the per process linkage into the hash tables and lives in struct task_struct. struct pid is given an indepedent lifetime, and holds pointers to each of the pid types. The independent life of struct pid simplifies attach_pid, and detach_pid, because we are always manipulating the list of pids and not the hash table. In addition in giving struct pid an indpendent life it makes the concept much more powerful. Kernel data structures can now embed a struct pid * instead of a pid_t and not suffer from pid wrap around problems or from keeping unnecessarily large amounts of memory allocated. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/fork.c')
-rw-r--r--kernel/fork.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/kernel/fork.c b/kernel/fork.c
index b1341205be27..03975d0467f9 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1315,17 +1315,19 @@ long do_fork(unsigned long clone_flags,
1315{ 1315{
1316 struct task_struct *p; 1316 struct task_struct *p;
1317 int trace = 0; 1317 int trace = 0;
1318 long pid = alloc_pidmap(); 1318 struct pid *pid = alloc_pid();
1319 long nr;
1319 1320
1320 if (pid < 0) 1321 if (!pid)
1321 return -EAGAIN; 1322 return -EAGAIN;
1323 nr = pid->nr;
1322 if (unlikely(current->ptrace)) { 1324 if (unlikely(current->ptrace)) {
1323 trace = fork_traceflag (clone_flags); 1325 trace = fork_traceflag (clone_flags);
1324 if (trace) 1326 if (trace)
1325 clone_flags |= CLONE_PTRACE; 1327 clone_flags |= CLONE_PTRACE;
1326 } 1328 }
1327 1329
1328 p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, pid); 1330 p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, nr);
1329 /* 1331 /*
1330 * Do this prior waking up the new thread - the thread pointer 1332 * Do this prior waking up the new thread - the thread pointer
1331 * might get invalid after that point, if the thread exits quickly. 1333 * might get invalid after that point, if the thread exits quickly.
@@ -1352,7 +1354,7 @@ long do_fork(unsigned long clone_flags,
1352 p->state = TASK_STOPPED; 1354 p->state = TASK_STOPPED;
1353 1355
1354 if (unlikely (trace)) { 1356 if (unlikely (trace)) {
1355 current->ptrace_message = pid; 1357 current->ptrace_message = nr;
1356 ptrace_notify ((trace << 8) | SIGTRAP); 1358 ptrace_notify ((trace << 8) | SIGTRAP);
1357 } 1359 }
1358 1360
@@ -1362,10 +1364,10 @@ long do_fork(unsigned long clone_flags,
1362 ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP); 1364 ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP);
1363 } 1365 }
1364 } else { 1366 } else {
1365 free_pidmap(pid); 1367 free_pid(pid);
1366 pid = PTR_ERR(p); 1368 nr = PTR_ERR(p);
1367 } 1369 }
1368 return pid; 1370 return nr;
1369} 1371}
1370 1372
1371#ifndef ARCH_MIN_MMSTRUCT_ALIGN 1373#ifndef ARCH_MIN_MMSTRUCT_ALIGN