diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2006-06-26 03:25:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 12:58:24 -0400 |
commit | 48e6484d49020dba3578ad117b461e8a391e8f0f (patch) | |
tree | 7824ca84bfe71c3fe2c09a1fedc31106fec4f500 /fs/proc/base.c | |
parent | 662795deb854b31501e0ffb42b7f0cce802c134a (diff) |
[PATCH] proc: Rewrite the proc dentry flush on exit optimization
To keep the dcache from filling up with dead /proc entries we flush them on
process exit. However over the years that code has gotten hairy with a
dentry_pointer and a lock in task_struct and misdocumented as a correctness
feature.
I have rewritten this code to look and see if we have a corresponding entry in
the dcache and if so flush it on process exit. This removes the extra fields
in the task_struct and allows me to trivially handle the case of a
/proc/<tgid>/task/<pid> entry as well as the current /proc/<pid> entries.
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 'fs/proc/base.c')
-rw-r--r-- | fs/proc/base.c | 134 |
1 files changed, 61 insertions, 73 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index c8636841bbcf..f435932e6432 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1352,16 +1352,6 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1352 | return 0; | 1352 | return 0; |
1353 | } | 1353 | } |
1354 | 1354 | ||
1355 | static void pid_base_iput(struct dentry *dentry, struct inode *inode) | ||
1356 | { | ||
1357 | struct task_struct *task = proc_task(inode); | ||
1358 | spin_lock(&task->proc_lock); | ||
1359 | if (task->proc_dentry == dentry) | ||
1360 | task->proc_dentry = NULL; | ||
1361 | spin_unlock(&task->proc_lock); | ||
1362 | iput(inode); | ||
1363 | } | ||
1364 | |||
1365 | static int pid_delete_dentry(struct dentry * dentry) | 1355 | static int pid_delete_dentry(struct dentry * dentry) |
1366 | { | 1356 | { |
1367 | /* Is the task we represent dead? | 1357 | /* Is the task we represent dead? |
@@ -1383,13 +1373,6 @@ static struct dentry_operations pid_dentry_operations = | |||
1383 | .d_delete = pid_delete_dentry, | 1373 | .d_delete = pid_delete_dentry, |
1384 | }; | 1374 | }; |
1385 | 1375 | ||
1386 | static struct dentry_operations pid_base_dentry_operations = | ||
1387 | { | ||
1388 | .d_revalidate = pid_revalidate, | ||
1389 | .d_iput = pid_base_iput, | ||
1390 | .d_delete = pid_delete_dentry, | ||
1391 | }; | ||
1392 | |||
1393 | /* Lookups */ | 1376 | /* Lookups */ |
1394 | 1377 | ||
1395 | static unsigned name_to_int(struct dentry *dentry) | 1378 | static unsigned name_to_int(struct dentry *dentry) |
@@ -1859,57 +1842,70 @@ static struct inode_operations proc_self_inode_operations = { | |||
1859 | }; | 1842 | }; |
1860 | 1843 | ||
1861 | /** | 1844 | /** |
1862 | * proc_pid_unhash - Unhash /proc/@pid entry from the dcache. | 1845 | * proc_flush_task - Remove dcache entries for @task from the /proc dcache. |
1863 | * @p: task that should be flushed. | 1846 | * |
1847 | * @task: task that should be flushed. | ||
1848 | * | ||
1849 | * Looks in the dcache for | ||
1850 | * /proc/@pid | ||
1851 | * /proc/@tgid/task/@pid | ||
1852 | * if either directory is present flushes it and all of it'ts children | ||
1853 | * from the dcache. | ||
1864 | * | 1854 | * |
1865 | * Drops the /proc/@pid dcache entry from the hash chains. | 1855 | * It is safe and reasonable to cache /proc entries for a task until |
1856 | * that task exits. After that they just clog up the dcache with | ||
1857 | * useless entries, possibly causing useful dcache entries to be | ||
1858 | * flushed instead. This routine is proved to flush those useless | ||
1859 | * dcache entries at process exit time. | ||
1866 | * | 1860 | * |
1867 | * Dropping /proc/@pid entries and detach_pid must be synchroneous, | 1861 | * NOTE: This routine is just an optimization so it does not guarantee |
1868 | * otherwise e.g. /proc/@pid/exe might point to the wrong executable, | 1862 | * that no dcache entries will exist at process exit time it |
1869 | * if the pid value is immediately reused. This is enforced by | 1863 | * just makes it very unlikely that any will persist. |
1870 | * - caller must acquire spin_lock(p->proc_lock) | ||
1871 | * - must be called before detach_pid() | ||
1872 | * - proc_pid_lookup acquires proc_lock, and checks that | ||
1873 | * the target is not dead by looking at the attach count | ||
1874 | * of PIDTYPE_PID. | ||
1875 | */ | 1864 | */ |
1876 | 1865 | void proc_flush_task(struct task_struct *task) | |
1877 | struct dentry *proc_pid_unhash(struct task_struct *p) | ||
1878 | { | 1866 | { |
1879 | struct dentry *proc_dentry; | 1867 | struct dentry *dentry, *leader, *dir; |
1868 | char buf[30]; | ||
1869 | struct qstr name; | ||
1870 | |||
1871 | name.name = buf; | ||
1872 | name.len = snprintf(buf, sizeof(buf), "%d", task->pid); | ||
1873 | dentry = d_hash_and_lookup(proc_mnt->mnt_root, &name); | ||
1874 | if (dentry) { | ||
1875 | shrink_dcache_parent(dentry); | ||
1876 | d_drop(dentry); | ||
1877 | dput(dentry); | ||
1878 | } | ||
1880 | 1879 | ||
1881 | proc_dentry = p->proc_dentry; | 1880 | if (thread_group_leader(task)) |
1882 | if (proc_dentry != NULL) { | 1881 | goto out; |
1883 | 1882 | ||
1884 | spin_lock(&dcache_lock); | 1883 | name.name = buf; |
1885 | spin_lock(&proc_dentry->d_lock); | 1884 | name.len = snprintf(buf, sizeof(buf), "%d", task->tgid); |
1886 | if (!d_unhashed(proc_dentry)) { | 1885 | leader = d_hash_and_lookup(proc_mnt->mnt_root, &name); |
1887 | dget_locked(proc_dentry); | 1886 | if (!leader) |
1888 | __d_drop(proc_dentry); | 1887 | goto out; |
1889 | spin_unlock(&proc_dentry->d_lock); | ||
1890 | } else { | ||
1891 | spin_unlock(&proc_dentry->d_lock); | ||
1892 | proc_dentry = NULL; | ||
1893 | } | ||
1894 | spin_unlock(&dcache_lock); | ||
1895 | } | ||
1896 | return proc_dentry; | ||
1897 | } | ||
1898 | 1888 | ||
1899 | /** | 1889 | name.name = "task"; |
1900 | * proc_pid_flush - recover memory used by stale /proc/@pid/x entries | 1890 | name.len = strlen(name.name); |
1901 | * @proc_dentry: directoy to prune. | 1891 | dir = d_hash_and_lookup(leader, &name); |
1902 | * | 1892 | if (!dir) |
1903 | * Shrink the /proc directory that was used by the just killed thread. | 1893 | goto out_put_leader; |
1904 | */ | 1894 | |
1905 | 1895 | name.name = buf; | |
1906 | void proc_pid_flush(struct dentry *proc_dentry) | 1896 | name.len = snprintf(buf, sizeof(buf), "%d", task->pid); |
1907 | { | 1897 | dentry = d_hash_and_lookup(dir, &name); |
1908 | might_sleep(); | 1898 | if (dentry) { |
1909 | if(proc_dentry != NULL) { | 1899 | shrink_dcache_parent(dentry); |
1910 | shrink_dcache_parent(proc_dentry); | 1900 | d_drop(dentry); |
1911 | dput(proc_dentry); | 1901 | dput(dentry); |
1912 | } | 1902 | } |
1903 | |||
1904 | dput(dir); | ||
1905 | out_put_leader: | ||
1906 | dput(leader); | ||
1907 | out: | ||
1908 | return; | ||
1913 | } | 1909 | } |
1914 | 1910 | ||
1915 | /* SMP-safe */ | 1911 | /* SMP-safe */ |
@@ -1919,7 +1915,6 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct | |||
1919 | struct inode *inode; | 1915 | struct inode *inode; |
1920 | struct proc_inode *ei; | 1916 | struct proc_inode *ei; |
1921 | unsigned tgid; | 1917 | unsigned tgid; |
1922 | int died; | ||
1923 | 1918 | ||
1924 | if (dentry->d_name.len == 4 && !memcmp(dentry->d_name.name,"self",4)) { | 1919 | if (dentry->d_name.len == 4 && !memcmp(dentry->d_name.name,"self",4)) { |
1925 | inode = new_inode(dir->i_sb); | 1920 | inode = new_inode(dir->i_sb); |
@@ -1965,23 +1960,16 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct | |||
1965 | inode->i_nlink = 4; | 1960 | inode->i_nlink = 4; |
1966 | #endif | 1961 | #endif |
1967 | 1962 | ||
1968 | dentry->d_op = &pid_base_dentry_operations; | 1963 | dentry->d_op = &pid_dentry_operations; |
1969 | 1964 | ||
1970 | died = 0; | ||
1971 | d_add(dentry, inode); | 1965 | d_add(dentry, inode); |
1972 | spin_lock(&task->proc_lock); | ||
1973 | task->proc_dentry = dentry; | ||
1974 | if (!pid_alive(task)) { | 1966 | if (!pid_alive(task)) { |
1975 | dentry = proc_pid_unhash(task); | 1967 | d_drop(dentry); |
1976 | died = 1; | 1968 | shrink_dcache_parent(dentry); |
1969 | goto out; | ||
1977 | } | 1970 | } |
1978 | spin_unlock(&task->proc_lock); | ||
1979 | 1971 | ||
1980 | put_task_struct(task); | 1972 | put_task_struct(task); |
1981 | if (died) { | ||
1982 | proc_pid_flush(dentry); | ||
1983 | goto out; | ||
1984 | } | ||
1985 | return NULL; | 1973 | return NULL; |
1986 | out: | 1974 | out: |
1987 | return ERR_PTR(-ENOENT); | 1975 | return ERR_PTR(-ENOENT); |
@@ -2024,7 +2012,7 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry | |||
2024 | inode->i_nlink = 3; | 2012 | inode->i_nlink = 3; |
2025 | #endif | 2013 | #endif |
2026 | 2014 | ||
2027 | dentry->d_op = &pid_base_dentry_operations; | 2015 | dentry->d_op = &pid_dentry_operations; |
2028 | 2016 | ||
2029 | d_add(dentry, inode); | 2017 | d_add(dentry, inode); |
2030 | 2018 | ||