aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/proc/base.c268
1 files changed, 163 insertions, 105 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 98eaeaa9fdd1..2236f7d3878e 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1545,8 +1545,6 @@ static struct file_operations proc_tgid_attr_operations;
1545static struct inode_operations proc_tgid_attr_inode_operations; 1545static struct inode_operations proc_tgid_attr_inode_operations;
1546#endif 1546#endif
1547 1547
1548static int get_tid_list(int index, unsigned int *tids, struct inode *dir);
1549
1550/* SMP-safe */ 1548/* SMP-safe */
1551static struct dentry *proc_pident_lookup(struct inode *dir, 1549static struct dentry *proc_pident_lookup(struct inode *dir,
1552 struct dentry *dentry, 1550 struct dentry *dentry,
@@ -2029,88 +2027,83 @@ out:
2029} 2027}
2030 2028
2031#define PROC_NUMBUF 10 2029#define PROC_NUMBUF 10
2032#define PROC_MAXPIDS 20
2033 2030
2034/* 2031/*
2035 * Get a few tgid's to return for filldir - we need to hold the 2032 * Find the first tgid to return to user space.
2036 * tasklist lock while doing this, and we must release it before 2033 *
2037 * we actually do the filldir itself, so we use a temp buffer.. 2034 * Usually this is just whatever follows &init_task, but if the users
2035 * buffer was too small to hold the full list or there was a seek into
2036 * the middle of the directory we have more work to do.
2037 *
2038 * In the case of a short read we start with find_task_by_pid.
2039 *
2040 * In the case of a seek we start with &init_task and walk nr
2041 * threads past it.
2038 */ 2042 */
2039static int get_tgid_list(int index, unsigned long version, unsigned int *tgids) 2043static struct task_struct *first_tgid(int tgid, int nr)
2040{ 2044{
2041 struct task_struct *p; 2045 struct task_struct *pos = NULL;
2042 int nr_tgids = 0;
2043
2044 index--;
2045 read_lock(&tasklist_lock); 2046 read_lock(&tasklist_lock);
2046 p = NULL; 2047 if (tgid && nr) {
2047 if (version) { 2048 pos = find_task_by_pid(tgid);
2048 p = find_task_by_pid(version); 2049 if (pos && !thread_group_leader(pos))
2049 if (p && !thread_group_leader(p)) 2050 pos = NULL;
2050 p = NULL; 2051 if (pos)
2052 nr = 0;
2051 } 2053 }
2054 /* If nr exceeds the number of processes get out quickly */
2055 if (nr && nr >= nr_processes())
2056 goto done;
2052 2057
2053 if (p) 2058 /* If we haven't found our starting place yet start with
2054 index = 0; 2059 * the init_task and walk nr tasks forward.
2055 else 2060 */
2056 p = next_task(&init_task); 2061 if (!pos && (nr >= 0))
2062 pos = next_task(&init_task);
2057 2063
2058 for ( ; p != &init_task; p = next_task(p)) { 2064 for (; pos && pid_alive(pos); pos = next_task(pos)) {
2059 int tgid = p->pid; 2065 if (--nr > 0)
2060 if (!pid_alive(p))
2061 continue;
2062 if (--index >= 0)
2063 continue; 2066 continue;
2064 tgids[nr_tgids] = tgid; 2067 get_task_struct(pos);
2065 nr_tgids++; 2068 goto done;
2066 if (nr_tgids >= PROC_MAXPIDS)
2067 break;
2068 } 2069 }
2070 pos = NULL;
2071done:
2069 read_unlock(&tasklist_lock); 2072 read_unlock(&tasklist_lock);
2070 return nr_tgids; 2073 return pos;
2071} 2074}
2072 2075
2073/* 2076/*
2074 * Get a few tid's to return for filldir - we need to hold the 2077 * Find the next task in the task list.
2075 * tasklist lock while doing this, and we must release it before 2078 * Return NULL if we loop or there is any error.
2076 * we actually do the filldir itself, so we use a temp buffer.. 2079 *
2080 * The reference to the input task_struct is released.
2077 */ 2081 */
2078static int get_tid_list(int index, unsigned int *tids, struct inode *dir) 2082static struct task_struct *next_tgid(struct task_struct *start)
2079{ 2083{
2080 struct task_struct *leader_task = proc_task(dir); 2084 struct task_struct *pos;
2081 struct task_struct *task = leader_task;
2082 int nr_tids = 0;
2083
2084 index -= 2;
2085 read_lock(&tasklist_lock); 2085 read_lock(&tasklist_lock);
2086 /* 2086 pos = start;
2087 * The starting point task (leader_task) might be an already 2087 if (pid_alive(start))
2088 * unlinked task, which cannot be used to access the task-list 2088 pos = next_task(start);
2089 * via next_thread(). 2089 if (pid_alive(pos) && (pos != &init_task)) {
2090 */ 2090 get_task_struct(pos);
2091 if (pid_alive(task)) do { 2091 goto done;
2092 int tid = task->pid; 2092 }
2093 2093 pos = NULL;
2094 if (--index >= 0) 2094done:
2095 continue;
2096 if (tids != NULL)
2097 tids[nr_tids] = tid;
2098 nr_tids++;
2099 if (nr_tids >= PROC_MAXPIDS)
2100 break;
2101 } while ((task = next_thread(task)) != leader_task);
2102 read_unlock(&tasklist_lock); 2095 read_unlock(&tasklist_lock);
2103 return nr_tids; 2096 put_task_struct(start);
2097 return pos;
2104} 2098}
2105 2099
2106/* for the /proc/ directory itself, after non-process stuff has been done */ 2100/* for the /proc/ directory itself, after non-process stuff has been done */
2107int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) 2101int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
2108{ 2102{
2109 unsigned int tgid_array[PROC_MAXPIDS];
2110 char buf[PROC_NUMBUF]; 2103 char buf[PROC_NUMBUF];
2111 unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY; 2104 unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY;
2112 unsigned int nr_tgids, i; 2105 struct task_struct *task;
2113 int next_tgid; 2106 int tgid;
2114 2107
2115 if (!nr) { 2108 if (!nr) {
2116 ino_t ino = fake_ino(0,PROC_TGID_INO); 2109 ino_t ino = fake_ino(0,PROC_TGID_INO);
@@ -2119,62 +2112,123 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
2119 filp->f_pos++; 2112 filp->f_pos++;
2120 nr++; 2113 nr++;
2121 } 2114 }
2115 nr -= 1;
2122 2116
2123 /* f_version caches the tgid value that the last readdir call couldn't 2117 /* f_version caches the tgid value that the last readdir call couldn't
2124 * return. lseek aka telldir automagically resets f_version to 0. 2118 * return. lseek aka telldir automagically resets f_version to 0.
2125 */ 2119 */
2126 next_tgid = filp->f_version; 2120 tgid = filp->f_version;
2127 filp->f_version = 0; 2121 filp->f_version = 0;
2128 for (;;) { 2122 for (task = first_tgid(tgid, nr);
2129 nr_tgids = get_tgid_list(nr, next_tgid, tgid_array); 2123 task;
2130 if (!nr_tgids) { 2124 task = next_tgid(task), filp->f_pos++) {
2131 /* no more entries ! */ 2125 int len;
2126 ino_t ino;
2127 tgid = task->pid;
2128 len = snprintf(buf, sizeof(buf), "%d", tgid);
2129 ino = fake_ino(tgid, PROC_TGID_INO);
2130 if (filldir(dirent, buf, len, filp->f_pos, ino, DT_DIR) < 0) {
2131 /* returning this tgid failed, save it as the first
2132 * pid for the next readir call */
2133 filp->f_version = tgid;
2134 put_task_struct(task);
2132 break; 2135 break;
2133 } 2136 }
2134 next_tgid = 0; 2137 }
2138 return 0;
2139}
2135 2140
2136 /* do not use the last found pid, reserve it for next_tgid */ 2141/*
2137 if (nr_tgids == PROC_MAXPIDS) { 2142 * Find the first tid of a thread group to return to user space.
2138 nr_tgids--; 2143 *
2139 next_tgid = tgid_array[nr_tgids]; 2144 * Usually this is just the thread group leader, but if the users
2140 } 2145 * buffer was too small or there was a seek into the middle of the
2146 * directory we have more work todo.
2147 *
2148 * In the case of a short read we start with find_task_by_pid.
2149 *
2150 * In the case of a seek we start with the leader and walk nr
2151 * threads past it.
2152 */
2153static struct task_struct *first_tid(struct task_struct *leader, int tid, int nr)
2154{
2155 struct task_struct *pos = NULL;
2156 read_lock(&tasklist_lock);
2141 2157
2142 for (i=0;i<nr_tgids;i++) { 2158 /* Attempt to start with the pid of a thread */
2143 int tgid = tgid_array[i]; 2159 if (tid && (nr > 0)) {
2144 ino_t ino = fake_ino(tgid,PROC_TGID_INO); 2160 pos = find_task_by_pid(tid);
2145 unsigned long j = PROC_NUMBUF; 2161 if (pos && (pos->group_leader != leader))
2162 pos = NULL;
2163 if (pos)
2164 nr = 0;
2165 }
2146 2166
2147 do 2167 /* If nr exceeds the number of threads there is nothing todo */
2148 buf[--j] = '0' + (tgid % 10); 2168 if (nr) {
2149 while ((tgid /= 10) != 0); 2169 int threads = 0;
2170 task_lock(leader);
2171 if (leader->signal)
2172 threads = atomic_read(&leader->signal->count);
2173 task_unlock(leader);
2174 if (nr >= threads)
2175 goto done;
2176 }
2150 2177
2151 if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino, DT_DIR) < 0) { 2178 /* If we haven't found our starting place yet start with the
2152 /* returning this tgid failed, save it as the first 2179 * leader and walk nr threads forward.
2153 * pid for the next readir call */ 2180 */
2154 filp->f_version = tgid_array[i]; 2181 if (!pos && (nr >= 0))
2155 goto out; 2182 pos = leader;
2156 } 2183
2157 filp->f_pos++; 2184 for (; pos && pid_alive(pos); pos = next_thread(pos)) {
2158 nr++; 2185 if (--nr > 0)
2159 } 2186 continue;
2187 get_task_struct(pos);
2188 goto done;
2160 } 2189 }
2161out: 2190 pos = NULL;
2162 return 0; 2191done:
2192 read_unlock(&tasklist_lock);
2193 return pos;
2194}
2195
2196/*
2197 * Find the next thread in the thread list.
2198 * Return NULL if there is an error or no next thread.
2199 *
2200 * The reference to the input task_struct is released.
2201 */
2202static struct task_struct *next_tid(struct task_struct *start)
2203{
2204 struct task_struct *pos;
2205 read_lock(&tasklist_lock);
2206 pos = start;
2207 if (pid_alive(start))
2208 pos = next_thread(start);
2209 if (pid_alive(pos) && (pos != start->group_leader))
2210 get_task_struct(pos);
2211 else
2212 pos = NULL;
2213 read_unlock(&tasklist_lock);
2214 put_task_struct(start);
2215 return pos;
2163} 2216}
2164 2217
2165/* for the /proc/TGID/task/ directories */ 2218/* for the /proc/TGID/task/ directories */
2166static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir) 2219static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir)
2167{ 2220{
2168 unsigned int tid_array[PROC_MAXPIDS];
2169 char buf[PROC_NUMBUF]; 2221 char buf[PROC_NUMBUF];
2170 unsigned int nr_tids, i;
2171 struct dentry *dentry = filp->f_dentry; 2222 struct dentry *dentry = filp->f_dentry;
2172 struct inode *inode = dentry->d_inode; 2223 struct inode *inode = dentry->d_inode;
2224 struct task_struct *leader = proc_task(inode);
2225 struct task_struct *task;
2173 int retval = -ENOENT; 2226 int retval = -ENOENT;
2174 ino_t ino; 2227 ino_t ino;
2228 int tid;
2175 unsigned long pos = filp->f_pos; /* avoiding "long long" filp->f_pos */ 2229 unsigned long pos = filp->f_pos; /* avoiding "long long" filp->f_pos */
2176 2230
2177 if (!pid_alive(proc_task(inode))) 2231 if (!pid_alive(leader))
2178 goto out; 2232 goto out;
2179 retval = 0; 2233 retval = 0;
2180 2234
@@ -2193,21 +2247,25 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi
2193 /* fall through */ 2247 /* fall through */
2194 } 2248 }
2195 2249
2196 nr_tids = get_tid_list(pos, tid_array, inode); 2250 /* f_version caches the tgid value that the last readdir call couldn't
2197 2251 * return. lseek aka telldir automagically resets f_version to 0.
2198 for (i = 0; i < nr_tids; i++) { 2252 */
2199 unsigned long j = PROC_NUMBUF; 2253 tid = filp->f_version;
2200 int tid = tid_array[i]; 2254 filp->f_version = 0;
2201 2255 for (task = first_tid(leader, tid, pos - 2);
2202 ino = fake_ino(tid,PROC_TID_INO); 2256 task;
2203 2257 task = next_tid(task), pos++) {
2204 do 2258 int len;
2205 buf[--j] = '0' + (tid % 10); 2259 tid = task->pid;
2206 while ((tid /= 10) != 0); 2260 len = snprintf(buf, sizeof(buf), "%d", tid);
2207 2261 ino = fake_ino(tid, PROC_TID_INO);
2208 if (filldir(dirent, buf+j, PROC_NUMBUF-j, pos, ino, DT_DIR) < 0) 2262 if (filldir(dirent, buf, len, pos, ino, DT_DIR < 0)) {
2263 /* returning this tgid failed, save it as the first
2264 * pid for the next readir call */
2265 filp->f_version = tid;
2266 put_task_struct(task);
2209 break; 2267 break;
2210 pos++; 2268 }
2211 } 2269 }
2212out: 2270out:
2213 filp->f_pos = pos; 2271 filp->f_pos = pos;