diff options
-rw-r--r-- | fs/proc/base.c | 104 | ||||
-rw-r--r-- | include/linux/pid.h | 1 | ||||
-rw-r--r-- | include/linux/sched.h | 11 | ||||
-rw-r--r-- | kernel/pid.c | 36 |
4 files changed, 83 insertions, 69 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 89c20d9d50bf..b18f3773dd43 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -2142,72 +2142,43 @@ out_no_task: | |||
2142 | } | 2142 | } |
2143 | 2143 | ||
2144 | /* | 2144 | /* |
2145 | * Find the first tgid to return to user space. | 2145 | * Find the first task with tgid >= tgid |
2146 | * | 2146 | * |
2147 | * Usually this is just whatever follows &init_task, but if the users | ||
2148 | * buffer was too small to hold the full list or there was a seek into | ||
2149 | * the middle of the directory we have more work to do. | ||
2150 | * | ||
2151 | * In the case of a short read we start with find_task_by_pid. | ||
2152 | * | ||
2153 | * In the case of a seek we start with &init_task and walk nr | ||
2154 | * threads past it. | ||
2155 | */ | 2147 | */ |
2156 | static struct task_struct *first_tgid(int tgid, unsigned int nr) | 2148 | static struct task_struct *next_tgid(unsigned int tgid) |
2157 | { | 2149 | { |
2158 | struct task_struct *pos; | 2150 | struct task_struct *task; |
2159 | rcu_read_lock(); | 2151 | struct pid *pid; |
2160 | if (tgid && nr) { | ||
2161 | pos = find_task_by_pid(tgid); | ||
2162 | if (pos && thread_group_leader(pos)) | ||
2163 | goto found; | ||
2164 | } | ||
2165 | /* If nr exceeds the number of processes get out quickly */ | ||
2166 | pos = NULL; | ||
2167 | if (nr && nr >= nr_processes()) | ||
2168 | goto done; | ||
2169 | |||
2170 | /* If we haven't found our starting place yet start with | ||
2171 | * the init_task and walk nr tasks forward. | ||
2172 | */ | ||
2173 | for (pos = next_task(&init_task); nr > 0; --nr) { | ||
2174 | pos = next_task(pos); | ||
2175 | if (pos == &init_task) { | ||
2176 | pos = NULL; | ||
2177 | goto done; | ||
2178 | } | ||
2179 | } | ||
2180 | found: | ||
2181 | get_task_struct(pos); | ||
2182 | done: | ||
2183 | rcu_read_unlock(); | ||
2184 | return pos; | ||
2185 | } | ||
2186 | 2152 | ||
2187 | /* | ||
2188 | * Find the next task in the task list. | ||
2189 | * Return NULL if we loop or there is any error. | ||
2190 | * | ||
2191 | * The reference to the input task_struct is released. | ||
2192 | */ | ||
2193 | static struct task_struct *next_tgid(struct task_struct *start) | ||
2194 | { | ||
2195 | struct task_struct *pos; | ||
2196 | rcu_read_lock(); | 2153 | rcu_read_lock(); |
2197 | pos = start; | 2154 | retry: |
2198 | if (pid_alive(start)) | 2155 | task = NULL; |
2199 | pos = next_task(start); | 2156 | pid = find_ge_pid(tgid); |
2200 | if (pid_alive(pos) && (pos != &init_task)) { | 2157 | if (pid) { |
2201 | get_task_struct(pos); | 2158 | tgid = pid->nr + 1; |
2202 | goto done; | 2159 | task = pid_task(pid, PIDTYPE_PID); |
2160 | /* What we to know is if the pid we have find is the | ||
2161 | * pid of a thread_group_leader. Testing for task | ||
2162 | * being a thread_group_leader is the obvious thing | ||
2163 | * todo but there is a window when it fails, due to | ||
2164 | * the pid transfer logic in de_thread. | ||
2165 | * | ||
2166 | * So we perform the straight forward test of seeing | ||
2167 | * if the pid we have found is the pid of a thread | ||
2168 | * group leader, and don't worry if the task we have | ||
2169 | * found doesn't happen to be a thread group leader. | ||
2170 | * As we don't care in the case of readdir. | ||
2171 | */ | ||
2172 | if (!task || !has_group_leader_pid(task)) | ||
2173 | goto retry; | ||
2174 | get_task_struct(task); | ||
2203 | } | 2175 | } |
2204 | pos = NULL; | ||
2205 | done: | ||
2206 | rcu_read_unlock(); | 2176 | rcu_read_unlock(); |
2207 | put_task_struct(start); | 2177 | return task; |
2208 | return pos; | ||
2209 | } | 2178 | } |
2210 | 2179 | ||
2180 | #define TGID_OFFSET (FIRST_PROCESS_ENTRY + (1 /* /proc/self */)) | ||
2181 | |||
2211 | /* for the /proc/ directory itself, after non-process stuff has been done */ | 2182 | /* for the /proc/ directory itself, after non-process stuff has been done */ |
2212 | int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) | 2183 | int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) |
2213 | { | 2184 | { |
@@ -2223,29 +2194,24 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
2223 | filp->f_pos++; | 2194 | filp->f_pos++; |
2224 | nr++; | 2195 | nr++; |
2225 | } | 2196 | } |
2226 | nr -= 1; | ||
2227 | 2197 | ||
2228 | /* f_version caches the tgid value that the last readdir call couldn't | 2198 | tgid = filp->f_pos - TGID_OFFSET; |
2229 | * return. lseek aka telldir automagically resets f_version to 0. | 2199 | for (task = next_tgid(tgid); |
2230 | */ | ||
2231 | tgid = filp->f_version; | ||
2232 | filp->f_version = 0; | ||
2233 | for (task = first_tgid(tgid, nr); | ||
2234 | task; | 2200 | task; |
2235 | task = next_tgid(task), filp->f_pos++) { | 2201 | put_task_struct(task), task = next_tgid(tgid + 1)) { |
2236 | int len; | 2202 | int len; |
2237 | ino_t ino; | 2203 | ino_t ino; |
2238 | tgid = task->pid; | 2204 | tgid = task->pid; |
2205 | filp->f_pos = tgid + TGID_OFFSET; | ||
2239 | len = snprintf(buf, sizeof(buf), "%d", tgid); | 2206 | len = snprintf(buf, sizeof(buf), "%d", tgid); |
2240 | ino = fake_ino(tgid, PROC_TGID_INO); | 2207 | ino = fake_ino(tgid, PROC_TGID_INO); |
2241 | if (filldir(dirent, buf, len, filp->f_pos, ino, DT_DIR) < 0) { | 2208 | if (filldir(dirent, buf, len, filp->f_pos, ino, DT_DIR) < 0) { |
2242 | /* returning this tgid failed, save it as the first | ||
2243 | * pid for the next readir call */ | ||
2244 | filp->f_version = tgid; | ||
2245 | put_task_struct(task); | 2209 | put_task_struct(task); |
2246 | break; | 2210 | goto out; |
2247 | } | 2211 | } |
2248 | } | 2212 | } |
2213 | filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET; | ||
2214 | out: | ||
2249 | return 0; | 2215 | return 0; |
2250 | } | 2216 | } |
2251 | 2217 | ||
diff --git a/include/linux/pid.h b/include/linux/pid.h index 93da7e2d9f30..359121086de1 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h | |||
@@ -89,6 +89,7 @@ extern struct pid *FASTCALL(find_pid(int nr)); | |||
89 | * Lookup a PID in the hash table, and return with it's count elevated. | 89 | * Lookup a PID in the hash table, and return with it's count elevated. |
90 | */ | 90 | */ |
91 | extern struct pid *find_get_pid(int nr); | 91 | extern struct pid *find_get_pid(int nr); |
92 | extern struct pid *find_ge_pid(int nr); | ||
92 | 93 | ||
93 | extern struct pid *alloc_pid(void); | 94 | extern struct pid *alloc_pid(void); |
94 | extern void FASTCALL(free_pid(struct pid *pid)); | 95 | extern void FASTCALL(free_pid(struct pid *pid)); |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 7ef899c47c29..be658e33bd26 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1358,6 +1358,17 @@ extern void wait_task_inactive(struct task_struct * p); | |||
1358 | /* de_thread depends on thread_group_leader not being a pid based check */ | 1358 | /* de_thread depends on thread_group_leader not being a pid based check */ |
1359 | #define thread_group_leader(p) (p == p->group_leader) | 1359 | #define thread_group_leader(p) (p == p->group_leader) |
1360 | 1360 | ||
1361 | /* Do to the insanities of de_thread it is possible for a process | ||
1362 | * to have the pid of the thread group leader without actually being | ||
1363 | * the thread group leader. For iteration through the pids in proc | ||
1364 | * all we care about is that we have a task with the appropriate | ||
1365 | * pid, we don't actually care if we have the right task. | ||
1366 | */ | ||
1367 | static inline int has_group_leader_pid(struct task_struct *p) | ||
1368 | { | ||
1369 | return p->pid == p->tgid; | ||
1370 | } | ||
1371 | |||
1361 | static inline struct task_struct *next_thread(const struct task_struct *p) | 1372 | static inline struct task_struct *next_thread(const struct task_struct *p) |
1362 | { | 1373 | { |
1363 | return list_entry(rcu_dereference(p->thread_group.next), | 1374 | return list_entry(rcu_dereference(p->thread_group.next), |
diff --git a/kernel/pid.c b/kernel/pid.c index 8387e8c68193..ed89a732432c 100644 --- a/kernel/pid.c +++ b/kernel/pid.c | |||
@@ -145,6 +145,23 @@ static int alloc_pidmap(void) | |||
145 | return -1; | 145 | return -1; |
146 | } | 146 | } |
147 | 147 | ||
148 | static int next_pidmap(int last) | ||
149 | { | ||
150 | int offset; | ||
151 | pidmap_t *map; | ||
152 | |||
153 | offset = (last + 1) & BITS_PER_PAGE_MASK; | ||
154 | map = &pidmap_array[(last + 1)/BITS_PER_PAGE]; | ||
155 | for (; map < &pidmap_array[PIDMAP_ENTRIES]; map++, offset = 0) { | ||
156 | if (unlikely(!map->page)) | ||
157 | continue; | ||
158 | offset = find_next_bit((map)->page, BITS_PER_PAGE, offset); | ||
159 | if (offset < BITS_PER_PAGE) | ||
160 | return mk_pid(map, offset); | ||
161 | } | ||
162 | return -1; | ||
163 | } | ||
164 | |||
148 | fastcall void put_pid(struct pid *pid) | 165 | fastcall void put_pid(struct pid *pid) |
149 | { | 166 | { |
150 | if (!pid) | 167 | if (!pid) |
@@ -303,6 +320,25 @@ struct pid *find_get_pid(pid_t nr) | |||
303 | } | 320 | } |
304 | 321 | ||
305 | /* | 322 | /* |
323 | * Used by proc to find the first pid that is greater then or equal to nr. | ||
324 | * | ||
325 | * If there is a pid at nr this function is exactly the same as find_pid. | ||
326 | */ | ||
327 | struct pid *find_ge_pid(int nr) | ||
328 | { | ||
329 | struct pid *pid; | ||
330 | |||
331 | do { | ||
332 | pid = find_pid(nr); | ||
333 | if (pid) | ||
334 | break; | ||
335 | nr = next_pidmap(nr); | ||
336 | } while (nr > 0); | ||
337 | |||
338 | return pid; | ||
339 | } | ||
340 | |||
341 | /* | ||
306 | * The pid hash table is scaled according to the amount of memory in the | 342 | * The pid hash table is scaled according to the amount of memory in the |
307 | * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or | 343 | * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or |
308 | * more. | 344 | * more. |