diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 103 |
1 files changed, 47 insertions, 56 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 44f6cf23b70e..43455776711e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -95,6 +95,14 @@ static void d_free(struct dentry *dentry) | |||
95 | call_rcu(&dentry->d_u.d_rcu, d_callback); | 95 | call_rcu(&dentry->d_u.d_rcu, d_callback); |
96 | } | 96 | } |
97 | 97 | ||
98 | static void dentry_lru_remove(struct dentry *dentry) | ||
99 | { | ||
100 | if (!list_empty(&dentry->d_lru)) { | ||
101 | list_del_init(&dentry->d_lru); | ||
102 | dentry_stat.nr_unused--; | ||
103 | } | ||
104 | } | ||
105 | |||
98 | /* | 106 | /* |
99 | * Release the dentry's inode, using the filesystem | 107 | * Release the dentry's inode, using the filesystem |
100 | * d_iput() operation if defined. | 108 | * d_iput() operation if defined. |
@@ -211,13 +219,7 @@ repeat: | |||
211 | unhash_it: | 219 | unhash_it: |
212 | __d_drop(dentry); | 220 | __d_drop(dentry); |
213 | kill_it: | 221 | kill_it: |
214 | /* If dentry was on d_lru list | 222 | dentry_lru_remove(dentry); |
215 | * delete it from there | ||
216 | */ | ||
217 | if (!list_empty(&dentry->d_lru)) { | ||
218 | list_del(&dentry->d_lru); | ||
219 | dentry_stat.nr_unused--; | ||
220 | } | ||
221 | dentry = d_kill(dentry); | 223 | dentry = d_kill(dentry); |
222 | if (dentry) | 224 | if (dentry) |
223 | goto repeat; | 225 | goto repeat; |
@@ -285,10 +287,7 @@ int d_invalidate(struct dentry * dentry) | |||
285 | static inline struct dentry * __dget_locked(struct dentry *dentry) | 287 | static inline struct dentry * __dget_locked(struct dentry *dentry) |
286 | { | 288 | { |
287 | atomic_inc(&dentry->d_count); | 289 | atomic_inc(&dentry->d_count); |
288 | if (!list_empty(&dentry->d_lru)) { | 290 | dentry_lru_remove(dentry); |
289 | dentry_stat.nr_unused--; | ||
290 | list_del_init(&dentry->d_lru); | ||
291 | } | ||
292 | return dentry; | 291 | return dentry; |
293 | } | 292 | } |
294 | 293 | ||
@@ -404,10 +403,7 @@ static void prune_one_dentry(struct dentry * dentry) | |||
404 | 403 | ||
405 | if (dentry->d_op && dentry->d_op->d_delete) | 404 | if (dentry->d_op && dentry->d_op->d_delete) |
406 | dentry->d_op->d_delete(dentry); | 405 | dentry->d_op->d_delete(dentry); |
407 | if (!list_empty(&dentry->d_lru)) { | 406 | dentry_lru_remove(dentry); |
408 | list_del(&dentry->d_lru); | ||
409 | dentry_stat.nr_unused--; | ||
410 | } | ||
411 | __d_drop(dentry); | 407 | __d_drop(dentry); |
412 | dentry = d_kill(dentry); | 408 | dentry = d_kill(dentry); |
413 | spin_lock(&dcache_lock); | 409 | spin_lock(&dcache_lock); |
@@ -596,10 +592,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
596 | 592 | ||
597 | /* detach this root from the system */ | 593 | /* detach this root from the system */ |
598 | spin_lock(&dcache_lock); | 594 | spin_lock(&dcache_lock); |
599 | if (!list_empty(&dentry->d_lru)) { | 595 | dentry_lru_remove(dentry); |
600 | dentry_stat.nr_unused--; | ||
601 | list_del_init(&dentry->d_lru); | ||
602 | } | ||
603 | __d_drop(dentry); | 596 | __d_drop(dentry); |
604 | spin_unlock(&dcache_lock); | 597 | spin_unlock(&dcache_lock); |
605 | 598 | ||
@@ -613,11 +606,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
613 | spin_lock(&dcache_lock); | 606 | spin_lock(&dcache_lock); |
614 | list_for_each_entry(loop, &dentry->d_subdirs, | 607 | list_for_each_entry(loop, &dentry->d_subdirs, |
615 | d_u.d_child) { | 608 | d_u.d_child) { |
616 | if (!list_empty(&loop->d_lru)) { | 609 | dentry_lru_remove(loop); |
617 | dentry_stat.nr_unused--; | ||
618 | list_del_init(&loop->d_lru); | ||
619 | } | ||
620 | |||
621 | __d_drop(loop); | 610 | __d_drop(loop); |
622 | cond_resched_lock(&dcache_lock); | 611 | cond_resched_lock(&dcache_lock); |
623 | } | 612 | } |
@@ -799,10 +788,7 @@ resume: | |||
799 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); | 788 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); |
800 | next = tmp->next; | 789 | next = tmp->next; |
801 | 790 | ||
802 | if (!list_empty(&dentry->d_lru)) { | 791 | dentry_lru_remove(dentry); |
803 | dentry_stat.nr_unused--; | ||
804 | list_del_init(&dentry->d_lru); | ||
805 | } | ||
806 | /* | 792 | /* |
807 | * move only zero ref count dentries to the end | 793 | * move only zero ref count dentries to the end |
808 | * of the unused list for prune_dcache | 794 | * of the unused list for prune_dcache |
@@ -1776,9 +1762,8 @@ shouldnt_be_hashed: | |||
1776 | * | 1762 | * |
1777 | * "buflen" should be positive. Caller holds the dcache_lock. | 1763 | * "buflen" should be positive. Caller holds the dcache_lock. |
1778 | */ | 1764 | */ |
1779 | static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, | 1765 | static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, |
1780 | struct dentry *root, struct vfsmount *rootmnt, | 1766 | struct path *root, char *buffer, int buflen) |
1781 | char *buffer, int buflen) | ||
1782 | { | 1767 | { |
1783 | char * end = buffer+buflen; | 1768 | char * end = buffer+buflen; |
1784 | char * retval; | 1769 | char * retval; |
@@ -1803,7 +1788,7 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, | |||
1803 | for (;;) { | 1788 | for (;;) { |
1804 | struct dentry * parent; | 1789 | struct dentry * parent; |
1805 | 1790 | ||
1806 | if (dentry == root && vfsmnt == rootmnt) | 1791 | if (dentry == root->dentry && vfsmnt == root->mnt) |
1807 | break; | 1792 | break; |
1808 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { | 1793 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { |
1809 | /* Global root? */ | 1794 | /* Global root? */ |
@@ -1844,13 +1829,23 @@ Elong: | |||
1844 | return ERR_PTR(-ENAMETOOLONG); | 1829 | return ERR_PTR(-ENAMETOOLONG); |
1845 | } | 1830 | } |
1846 | 1831 | ||
1847 | /* write full pathname into buffer and return start of pathname */ | 1832 | /** |
1848 | char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, | 1833 | * d_path - return the path of a dentry |
1849 | char *buf, int buflen) | 1834 | * @path: path to report |
1835 | * @buf: buffer to return value in | ||
1836 | * @buflen: buffer length | ||
1837 | * | ||
1838 | * Convert a dentry into an ASCII path name. If the entry has been deleted | ||
1839 | * the string " (deleted)" is appended. Note that this is ambiguous. | ||
1840 | * | ||
1841 | * Returns the buffer or an error code if the path was too long. | ||
1842 | * | ||
1843 | * "buflen" should be positive. Caller holds the dcache_lock. | ||
1844 | */ | ||
1845 | char *d_path(struct path *path, char *buf, int buflen) | ||
1850 | { | 1846 | { |
1851 | char *res; | 1847 | char *res; |
1852 | struct vfsmount *rootmnt; | 1848 | struct path root; |
1853 | struct dentry *root; | ||
1854 | 1849 | ||
1855 | /* | 1850 | /* |
1856 | * We have various synthetic filesystems that never get mounted. On | 1851 | * We have various synthetic filesystems that never get mounted. On |
@@ -1859,18 +1854,17 @@ char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, | |||
1859 | * user wants to identify the object in /proc/pid/fd/. The little hack | 1854 | * user wants to identify the object in /proc/pid/fd/. The little hack |
1860 | * below allows us to generate a name for these objects on demand: | 1855 | * below allows us to generate a name for these objects on demand: |
1861 | */ | 1856 | */ |
1862 | if (dentry->d_op && dentry->d_op->d_dname) | 1857 | if (path->dentry->d_op && path->dentry->d_op->d_dname) |
1863 | return dentry->d_op->d_dname(dentry, buf, buflen); | 1858 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); |
1864 | 1859 | ||
1865 | read_lock(¤t->fs->lock); | 1860 | read_lock(¤t->fs->lock); |
1866 | rootmnt = mntget(current->fs->rootmnt); | 1861 | root = current->fs->root; |
1867 | root = dget(current->fs->root); | 1862 | path_get(¤t->fs->root); |
1868 | read_unlock(¤t->fs->lock); | 1863 | read_unlock(¤t->fs->lock); |
1869 | spin_lock(&dcache_lock); | 1864 | spin_lock(&dcache_lock); |
1870 | res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen); | 1865 | res = __d_path(path->dentry, path->mnt, &root, buf, buflen); |
1871 | spin_unlock(&dcache_lock); | 1866 | spin_unlock(&dcache_lock); |
1872 | dput(root); | 1867 | path_put(&root); |
1873 | mntput(rootmnt); | ||
1874 | return res; | 1868 | return res; |
1875 | } | 1869 | } |
1876 | 1870 | ||
@@ -1916,28 +1910,27 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen, | |||
1916 | asmlinkage long sys_getcwd(char __user *buf, unsigned long size) | 1910 | asmlinkage long sys_getcwd(char __user *buf, unsigned long size) |
1917 | { | 1911 | { |
1918 | int error; | 1912 | int error; |
1919 | struct vfsmount *pwdmnt, *rootmnt; | 1913 | struct path pwd, root; |
1920 | struct dentry *pwd, *root; | ||
1921 | char *page = (char *) __get_free_page(GFP_USER); | 1914 | char *page = (char *) __get_free_page(GFP_USER); |
1922 | 1915 | ||
1923 | if (!page) | 1916 | if (!page) |
1924 | return -ENOMEM; | 1917 | return -ENOMEM; |
1925 | 1918 | ||
1926 | read_lock(¤t->fs->lock); | 1919 | read_lock(¤t->fs->lock); |
1927 | pwdmnt = mntget(current->fs->pwdmnt); | 1920 | pwd = current->fs->pwd; |
1928 | pwd = dget(current->fs->pwd); | 1921 | path_get(¤t->fs->pwd); |
1929 | rootmnt = mntget(current->fs->rootmnt); | 1922 | root = current->fs->root; |
1930 | root = dget(current->fs->root); | 1923 | path_get(¤t->fs->root); |
1931 | read_unlock(¤t->fs->lock); | 1924 | read_unlock(¤t->fs->lock); |
1932 | 1925 | ||
1933 | error = -ENOENT; | 1926 | error = -ENOENT; |
1934 | /* Has the current directory has been unlinked? */ | 1927 | /* Has the current directory has been unlinked? */ |
1935 | spin_lock(&dcache_lock); | 1928 | spin_lock(&dcache_lock); |
1936 | if (pwd->d_parent == pwd || !d_unhashed(pwd)) { | 1929 | if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) { |
1937 | unsigned long len; | 1930 | unsigned long len; |
1938 | char * cwd; | 1931 | char * cwd; |
1939 | 1932 | ||
1940 | cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE); | 1933 | cwd = __d_path(pwd.dentry, pwd.mnt, &root, page, PAGE_SIZE); |
1941 | spin_unlock(&dcache_lock); | 1934 | spin_unlock(&dcache_lock); |
1942 | 1935 | ||
1943 | error = PTR_ERR(cwd); | 1936 | error = PTR_ERR(cwd); |
@@ -1955,10 +1948,8 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) | |||
1955 | spin_unlock(&dcache_lock); | 1948 | spin_unlock(&dcache_lock); |
1956 | 1949 | ||
1957 | out: | 1950 | out: |
1958 | dput(pwd); | 1951 | path_put(&pwd); |
1959 | mntput(pwdmnt); | 1952 | path_put(&root); |
1960 | dput(root); | ||
1961 | mntput(rootmnt); | ||
1962 | free_page((unsigned long) page); | 1953 | free_page((unsigned long) page); |
1963 | return error; | 1954 | return error; |
1964 | } | 1955 | } |