diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 108 |
1 files changed, 48 insertions, 60 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index d9ca1e5ceb92..43455776711e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -89,12 +89,20 @@ static void d_free(struct dentry *dentry) | |||
89 | if (dentry->d_op && dentry->d_op->d_release) | 89 | if (dentry->d_op && dentry->d_op->d_release) |
90 | dentry->d_op->d_release(dentry); | 90 | dentry->d_op->d_release(dentry); |
91 | /* if dentry was never inserted into hash, immediate free is OK */ | 91 | /* if dentry was never inserted into hash, immediate free is OK */ |
92 | if (dentry->d_hash.pprev == NULL) | 92 | if (hlist_unhashed(&dentry->d_hash)) |
93 | __d_free(dentry); | 93 | __d_free(dentry); |
94 | else | 94 | else |
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 |
@@ -1408,9 +1394,6 @@ void d_delete(struct dentry * dentry) | |||
1408 | if (atomic_read(&dentry->d_count) == 1) { | 1394 | if (atomic_read(&dentry->d_count) == 1) { |
1409 | dentry_iput(dentry); | 1395 | dentry_iput(dentry); |
1410 | fsnotify_nameremove(dentry, isdir); | 1396 | fsnotify_nameremove(dentry, isdir); |
1411 | |||
1412 | /* remove this and other inotify debug checks after 2.6.18 */ | ||
1413 | dentry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED; | ||
1414 | return; | 1397 | return; |
1415 | } | 1398 | } |
1416 | 1399 | ||
@@ -1779,9 +1762,8 @@ shouldnt_be_hashed: | |||
1779 | * | 1762 | * |
1780 | * "buflen" should be positive. Caller holds the dcache_lock. | 1763 | * "buflen" should be positive. Caller holds the dcache_lock. |
1781 | */ | 1764 | */ |
1782 | static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, | 1765 | static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, |
1783 | struct dentry *root, struct vfsmount *rootmnt, | 1766 | struct path *root, char *buffer, int buflen) |
1784 | char *buffer, int buflen) | ||
1785 | { | 1767 | { |
1786 | char * end = buffer+buflen; | 1768 | char * end = buffer+buflen; |
1787 | char * retval; | 1769 | char * retval; |
@@ -1806,7 +1788,7 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, | |||
1806 | for (;;) { | 1788 | for (;;) { |
1807 | struct dentry * parent; | 1789 | struct dentry * parent; |
1808 | 1790 | ||
1809 | if (dentry == root && vfsmnt == rootmnt) | 1791 | if (dentry == root->dentry && vfsmnt == root->mnt) |
1810 | break; | 1792 | break; |
1811 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { | 1793 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { |
1812 | /* Global root? */ | 1794 | /* Global root? */ |
@@ -1847,13 +1829,23 @@ Elong: | |||
1847 | return ERR_PTR(-ENAMETOOLONG); | 1829 | return ERR_PTR(-ENAMETOOLONG); |
1848 | } | 1830 | } |
1849 | 1831 | ||
1850 | /* write full pathname into buffer and return start of pathname */ | 1832 | /** |
1851 | char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, | 1833 | * d_path - return the path of a dentry |
1852 | 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) | ||
1853 | { | 1846 | { |
1854 | char *res; | 1847 | char *res; |
1855 | struct vfsmount *rootmnt; | 1848 | struct path root; |
1856 | struct dentry *root; | ||
1857 | 1849 | ||
1858 | /* | 1850 | /* |
1859 | * We have various synthetic filesystems that never get mounted. On | 1851 | * We have various synthetic filesystems that never get mounted. On |
@@ -1862,18 +1854,17 @@ char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, | |||
1862 | * 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 |
1863 | * 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: |
1864 | */ | 1856 | */ |
1865 | if (dentry->d_op && dentry->d_op->d_dname) | 1857 | if (path->dentry->d_op && path->dentry->d_op->d_dname) |
1866 | return dentry->d_op->d_dname(dentry, buf, buflen); | 1858 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); |
1867 | 1859 | ||
1868 | read_lock(¤t->fs->lock); | 1860 | read_lock(¤t->fs->lock); |
1869 | rootmnt = mntget(current->fs->rootmnt); | 1861 | root = current->fs->root; |
1870 | root = dget(current->fs->root); | 1862 | path_get(¤t->fs->root); |
1871 | read_unlock(¤t->fs->lock); | 1863 | read_unlock(¤t->fs->lock); |
1872 | spin_lock(&dcache_lock); | 1864 | spin_lock(&dcache_lock); |
1873 | res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen); | 1865 | res = __d_path(path->dentry, path->mnt, &root, buf, buflen); |
1874 | spin_unlock(&dcache_lock); | 1866 | spin_unlock(&dcache_lock); |
1875 | dput(root); | 1867 | path_put(&root); |
1876 | mntput(rootmnt); | ||
1877 | return res; | 1868 | return res; |
1878 | } | 1869 | } |
1879 | 1870 | ||
@@ -1919,28 +1910,27 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen, | |||
1919 | asmlinkage long sys_getcwd(char __user *buf, unsigned long size) | 1910 | asmlinkage long sys_getcwd(char __user *buf, unsigned long size) |
1920 | { | 1911 | { |
1921 | int error; | 1912 | int error; |
1922 | struct vfsmount *pwdmnt, *rootmnt; | 1913 | struct path pwd, root; |
1923 | struct dentry *pwd, *root; | ||
1924 | char *page = (char *) __get_free_page(GFP_USER); | 1914 | char *page = (char *) __get_free_page(GFP_USER); |
1925 | 1915 | ||
1926 | if (!page) | 1916 | if (!page) |
1927 | return -ENOMEM; | 1917 | return -ENOMEM; |
1928 | 1918 | ||
1929 | read_lock(¤t->fs->lock); | 1919 | read_lock(¤t->fs->lock); |
1930 | pwdmnt = mntget(current->fs->pwdmnt); | 1920 | pwd = current->fs->pwd; |
1931 | pwd = dget(current->fs->pwd); | 1921 | path_get(¤t->fs->pwd); |
1932 | rootmnt = mntget(current->fs->rootmnt); | 1922 | root = current->fs->root; |
1933 | root = dget(current->fs->root); | 1923 | path_get(¤t->fs->root); |
1934 | read_unlock(¤t->fs->lock); | 1924 | read_unlock(¤t->fs->lock); |
1935 | 1925 | ||
1936 | error = -ENOENT; | 1926 | error = -ENOENT; |
1937 | /* Has the current directory has been unlinked? */ | 1927 | /* Has the current directory has been unlinked? */ |
1938 | spin_lock(&dcache_lock); | 1928 | spin_lock(&dcache_lock); |
1939 | if (pwd->d_parent == pwd || !d_unhashed(pwd)) { | 1929 | if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) { |
1940 | unsigned long len; | 1930 | unsigned long len; |
1941 | char * cwd; | 1931 | char * cwd; |
1942 | 1932 | ||
1943 | cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE); | 1933 | cwd = __d_path(pwd.dentry, pwd.mnt, &root, page, PAGE_SIZE); |
1944 | spin_unlock(&dcache_lock); | 1934 | spin_unlock(&dcache_lock); |
1945 | 1935 | ||
1946 | error = PTR_ERR(cwd); | 1936 | error = PTR_ERR(cwd); |
@@ -1958,10 +1948,8 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) | |||
1958 | spin_unlock(&dcache_lock); | 1948 | spin_unlock(&dcache_lock); |
1959 | 1949 | ||
1960 | out: | 1950 | out: |
1961 | dput(pwd); | 1951 | path_put(&pwd); |
1962 | mntput(pwdmnt); | 1952 | path_put(&root); |
1963 | dput(root); | ||
1964 | mntput(rootmnt); | ||
1965 | free_page((unsigned long) page); | 1953 | free_page((unsigned long) page); |
1966 | return error; | 1954 | return error; |
1967 | } | 1955 | } |