From: Manfred Spraul readdir on /proc has two problems: reading all entries is O(N^2), and entries are overlooked if tasks die in the middle of readdir: the readdir implementation remembers the offset into the task list, and if a task (actually: process) that was returned by previous readdir calls exits, then a random entry is dropped. The attached patch fixes the O(N^2) by using f_version to store the pid of the task that should be returned next. This speeds up reading /proc to O(N). Additionally, it mitigates the effects of dying tasks: Tasks are skipped only if the task whose pid is stored in f_version exits, all other task deaths have no effect. Unfortunately the code has a bad worst case behavior: if the targeted task exits and a new task with the same pid is created, then all entries in the task list between old and new position are dropped. This should be rare. fs/proc/base.c | 25 +++++++++++++++++++++---- 1 files changed, 21 insertions(+), 4 deletions(-) diff -puN fs/proc/base.c~proc_pid_lookup-speedup fs/proc/base.c --- 25/fs/proc/base.c~proc_pid_lookup-speedup 2004-01-06 09:20:15.000000000 -0800 +++ 25-akpm/fs/proc/base.c 2004-01-06 09:24:44.000000000 -0800 @@ -1669,14 +1669,26 @@ out: * tasklist lock while doing this, and we must release it before * we actually do the filldir itself, so we use a temp buffer.. */ -static int get_tgid_list(int index, unsigned int *tgids) +static int get_tgid_list(int index, unsigned long version, unsigned int *tgids) { struct task_struct *p; int nr_tgids = 0; index--; read_lock(&tasklist_lock); - for_each_process(p) { + p = NULL; + if (version) { + p = find_task_by_pid(version); + if (!thread_group_leader(p)) + p = NULL; + } + + if (p) + index = 0; + else + p = next_task(&init_task); + + for ( ; p != &init_task; p = next_task(p)) { int tgid = p->pid; if (!pid_alive(p)) continue; @@ -1739,7 +1751,10 @@ int proc_pid_readdir(struct file * filp, nr++; } - nr_tgids = get_tgid_list(nr, tgid_array); + /* + * f_version caches the last tgid which was returned from readdir + */ + nr_tgids = get_tgid_list(nr, filp->f_version, tgid_array); for (i = 0; i < nr_tgids; i++) { int tgid = tgid_array[i]; @@ -1748,8 +1763,10 @@ int proc_pid_readdir(struct file * filp, do buf[--j] = '0' + (tgid % 10); while (tgid/=10); - if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino, DT_DIR) < 0) + if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino, DT_DIR) < 0) { + filp->f_version = tgid; break; + } filp->f_pos++; } return 0; _