diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2006-06-26 03:25:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 12:58:24 -0400 |
commit | 6e66b52bf587f0dd9a8e0a581b9570e5c1969e33 (patch) | |
tree | 18b630e89490f7e01ee45f07a427fded50a1c6cf | |
parent | 0f2fe20f55c85f26efaf14feeb69c7c2eb3f7a75 (diff) |
[PATCH] proc: Fix the link count for /proc/<pid>/task
Use getattr to get an accurate link count when needed. This is cheaper and
more accurate than trying to derive it by walking the thread list of a
process.
Especially as it happens when needed stat instead of at readdir time.
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>
-rw-r--r-- | fs/proc/base.c | 21 |
1 files changed, 19 insertions, 2 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index a85b073408e0..29539c2268a3 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1532,6 +1532,7 @@ out: | |||
1532 | 1532 | ||
1533 | static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir); | 1533 | static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir); |
1534 | static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd); | 1534 | static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd); |
1535 | static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); | ||
1535 | 1536 | ||
1536 | static struct file_operations proc_fd_operations = { | 1537 | static struct file_operations proc_fd_operations = { |
1537 | .read = generic_read_dir, | 1538 | .read = generic_read_dir, |
@@ -1552,6 +1553,7 @@ static struct inode_operations proc_fd_inode_operations = { | |||
1552 | 1553 | ||
1553 | static struct inode_operations proc_task_inode_operations = { | 1554 | static struct inode_operations proc_task_inode_operations = { |
1554 | .lookup = proc_task_lookup, | 1555 | .lookup = proc_task_lookup, |
1556 | .getattr = proc_task_getattr, | ||
1555 | }; | 1557 | }; |
1556 | 1558 | ||
1557 | #ifdef CONFIG_SECURITY | 1559 | #ifdef CONFIG_SECURITY |
@@ -1658,7 +1660,7 @@ static struct dentry *proc_pident_lookup(struct inode *dir, | |||
1658 | */ | 1660 | */ |
1659 | switch(p->type) { | 1661 | switch(p->type) { |
1660 | case PROC_TGID_TASK: | 1662 | case PROC_TGID_TASK: |
1661 | inode->i_nlink = 2 + get_tid_list(2, NULL, dir); | 1663 | inode->i_nlink = 2; |
1662 | inode->i_op = &proc_task_inode_operations; | 1664 | inode->i_op = &proc_task_inode_operations; |
1663 | inode->i_fop = &proc_task_operations; | 1665 | inode->i_fop = &proc_task_operations; |
1664 | break; | 1666 | break; |
@@ -2261,7 +2263,6 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi | |||
2261 | } | 2263 | } |
2262 | 2264 | ||
2263 | nr_tids = get_tid_list(pos, tid_array, inode); | 2265 | nr_tids = get_tid_list(pos, tid_array, inode); |
2264 | inode->i_nlink = pos + nr_tids; | ||
2265 | 2266 | ||
2266 | for (i = 0; i < nr_tids; i++) { | 2267 | for (i = 0; i < nr_tids; i++) { |
2267 | unsigned long j = PROC_NUMBUF; | 2268 | unsigned long j = PROC_NUMBUF; |
@@ -2281,3 +2282,19 @@ out: | |||
2281 | filp->f_pos = pos; | 2282 | filp->f_pos = pos; |
2282 | return retval; | 2283 | return retval; |
2283 | } | 2284 | } |
2285 | |||
2286 | static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | ||
2287 | { | ||
2288 | struct inode *inode = dentry->d_inode; | ||
2289 | struct task_struct *p = proc_task(inode); | ||
2290 | generic_fillattr(inode, stat); | ||
2291 | |||
2292 | if (pid_alive(p)) { | ||
2293 | task_lock(p); | ||
2294 | if (p->signal) | ||
2295 | stat->nlink += atomic_read(&p->signal->count); | ||
2296 | task_unlock(p); | ||
2297 | } | ||
2298 | |||
2299 | return 0; | ||
2300 | } | ||