diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 154 |
1 files changed, 102 insertions, 52 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 43455776711e..6068c25b393c 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/syscalls.h> | 17 | #include <linux/syscalls.h> |
18 | #include <linux/string.h> | 18 | #include <linux/string.h> |
19 | #include <linux/mm.h> | 19 | #include <linux/mm.h> |
20 | #include <linux/fdtable.h> | ||
20 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
21 | #include <linux/fsnotify.h> | 22 | #include <linux/fsnotify.h> |
22 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
@@ -106,9 +107,10 @@ static void dentry_lru_remove(struct dentry *dentry) | |||
106 | /* | 107 | /* |
107 | * Release the dentry's inode, using the filesystem | 108 | * Release the dentry's inode, using the filesystem |
108 | * d_iput() operation if defined. | 109 | * d_iput() operation if defined. |
109 | * Called with dcache_lock and per dentry lock held, drops both. | ||
110 | */ | 110 | */ |
111 | static void dentry_iput(struct dentry * dentry) | 111 | static void dentry_iput(struct dentry * dentry) |
112 | __releases(dentry->d_lock) | ||
113 | __releases(dcache_lock) | ||
112 | { | 114 | { |
113 | struct inode *inode = dentry->d_inode; | 115 | struct inode *inode = dentry->d_inode; |
114 | if (inode) { | 116 | if (inode) { |
@@ -132,12 +134,13 @@ static void dentry_iput(struct dentry * dentry) | |||
132 | * d_kill - kill dentry and return parent | 134 | * d_kill - kill dentry and return parent |
133 | * @dentry: dentry to kill | 135 | * @dentry: dentry to kill |
134 | * | 136 | * |
135 | * Called with dcache_lock and d_lock, releases both. The dentry must | 137 | * The dentry must already be unhashed and removed from the LRU. |
136 | * already be unhashed and removed from the LRU. | ||
137 | * | 138 | * |
138 | * If this is the root of the dentry tree, return NULL. | 139 | * If this is the root of the dentry tree, return NULL. |
139 | */ | 140 | */ |
140 | static struct dentry *d_kill(struct dentry *dentry) | 141 | static struct dentry *d_kill(struct dentry *dentry) |
142 | __releases(dentry->d_lock) | ||
143 | __releases(dcache_lock) | ||
141 | { | 144 | { |
142 | struct dentry *parent; | 145 | struct dentry *parent; |
143 | 146 | ||
@@ -383,11 +386,11 @@ restart: | |||
383 | * Try to prune ancestors as well. This is necessary to prevent | 386 | * Try to prune ancestors as well. This is necessary to prevent |
384 | * quadratic behavior of shrink_dcache_parent(), but is also expected | 387 | * quadratic behavior of shrink_dcache_parent(), but is also expected |
385 | * to be beneficial in reducing dentry cache fragmentation. | 388 | * to be beneficial in reducing dentry cache fragmentation. |
386 | * | ||
387 | * Called with dcache_lock, drops it and then regains. | ||
388 | * Called with dentry->d_lock held, drops it. | ||
389 | */ | 389 | */ |
390 | static void prune_one_dentry(struct dentry * dentry) | 390 | static void prune_one_dentry(struct dentry * dentry) |
391 | __releases(dentry->d_lock) | ||
392 | __releases(dcache_lock) | ||
393 | __acquires(dcache_lock) | ||
391 | { | 394 | { |
392 | __d_drop(dentry); | 395 | __d_drop(dentry); |
393 | dentry = d_kill(dentry); | 396 | dentry = d_kill(dentry); |
@@ -1604,10 +1607,9 @@ static int d_isparent(struct dentry *p1, struct dentry *p2) | |||
1604 | * | 1607 | * |
1605 | * Note: If ever the locking in lock_rename() changes, then please | 1608 | * Note: If ever the locking in lock_rename() changes, then please |
1606 | * remember to update this too... | 1609 | * remember to update this too... |
1607 | * | ||
1608 | * On return, dcache_lock will have been unlocked. | ||
1609 | */ | 1610 | */ |
1610 | static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias) | 1611 | static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias) |
1612 | __releases(dcache_lock) | ||
1611 | { | 1613 | { |
1612 | struct mutex *m1 = NULL, *m2 = NULL; | 1614 | struct mutex *m1 = NULL, *m2 = NULL; |
1613 | struct dentry *ret; | 1615 | struct dentry *ret; |
@@ -1743,15 +1745,27 @@ out_nolock: | |||
1743 | shouldnt_be_hashed: | 1745 | shouldnt_be_hashed: |
1744 | spin_unlock(&dcache_lock); | 1746 | spin_unlock(&dcache_lock); |
1745 | BUG(); | 1747 | BUG(); |
1746 | goto shouldnt_be_hashed; | 1748 | } |
1749 | |||
1750 | static int prepend(char **buffer, int *buflen, const char *str, int namelen) | ||
1751 | { | ||
1752 | *buflen -= namelen; | ||
1753 | if (*buflen < 0) | ||
1754 | return -ENAMETOOLONG; | ||
1755 | *buffer -= namelen; | ||
1756 | memcpy(*buffer, str, namelen); | ||
1757 | return 0; | ||
1758 | } | ||
1759 | |||
1760 | static int prepend_name(char **buffer, int *buflen, struct qstr *name) | ||
1761 | { | ||
1762 | return prepend(buffer, buflen, name->name, name->len); | ||
1747 | } | 1763 | } |
1748 | 1764 | ||
1749 | /** | 1765 | /** |
1750 | * d_path - return the path of a dentry | 1766 | * __d_path - return the path of a dentry |
1751 | * @dentry: dentry to report | 1767 | * @path: the dentry/vfsmount to report |
1752 | * @vfsmnt: vfsmnt to which the dentry belongs | 1768 | * @root: root vfsmnt/dentry (may be modified by this function) |
1753 | * @root: root dentry | ||
1754 | * @rootmnt: vfsmnt to which the root dentry belongs | ||
1755 | * @buffer: buffer to return value in | 1769 | * @buffer: buffer to return value in |
1756 | * @buflen: buffer length | 1770 | * @buflen: buffer length |
1757 | * | 1771 | * |
@@ -1761,23 +1775,23 @@ shouldnt_be_hashed: | |||
1761 | * Returns the buffer or an error code if the path was too long. | 1775 | * Returns the buffer or an error code if the path was too long. |
1762 | * | 1776 | * |
1763 | * "buflen" should be positive. Caller holds the dcache_lock. | 1777 | * "buflen" should be positive. Caller holds the dcache_lock. |
1778 | * | ||
1779 | * If path is not reachable from the supplied root, then the value of | ||
1780 | * root is changed (without modifying refcounts). | ||
1764 | */ | 1781 | */ |
1765 | static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, | 1782 | char *__d_path(const struct path *path, struct path *root, |
1766 | struct path *root, char *buffer, int buflen) | 1783 | char *buffer, int buflen) |
1767 | { | 1784 | { |
1768 | char * end = buffer+buflen; | 1785 | struct dentry *dentry = path->dentry; |
1769 | char * retval; | 1786 | struct vfsmount *vfsmnt = path->mnt; |
1770 | int namelen; | 1787 | char *end = buffer + buflen; |
1771 | 1788 | char *retval; | |
1772 | *--end = '\0'; | 1789 | |
1773 | buflen--; | 1790 | spin_lock(&vfsmount_lock); |
1774 | if (!IS_ROOT(dentry) && d_unhashed(dentry)) { | 1791 | prepend(&end, &buflen, "\0", 1); |
1775 | buflen -= 10; | 1792 | if (!IS_ROOT(dentry) && d_unhashed(dentry) && |
1776 | end -= 10; | 1793 | (prepend(&end, &buflen, " (deleted)", 10) != 0)) |
1777 | if (buflen < 0) | ||
1778 | goto Elong; | 1794 | goto Elong; |
1779 | memcpy(end, " (deleted)", 10); | ||
1780 | } | ||
1781 | 1795 | ||
1782 | if (buflen < 1) | 1796 | if (buflen < 1) |
1783 | goto Elong; | 1797 | goto Elong; |
@@ -1792,41 +1806,37 @@ static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, | |||
1792 | break; | 1806 | break; |
1793 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { | 1807 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { |
1794 | /* Global root? */ | 1808 | /* Global root? */ |
1795 | spin_lock(&vfsmount_lock); | ||
1796 | if (vfsmnt->mnt_parent == vfsmnt) { | 1809 | if (vfsmnt->mnt_parent == vfsmnt) { |
1797 | spin_unlock(&vfsmount_lock); | ||
1798 | goto global_root; | 1810 | goto global_root; |
1799 | } | 1811 | } |
1800 | dentry = vfsmnt->mnt_mountpoint; | 1812 | dentry = vfsmnt->mnt_mountpoint; |
1801 | vfsmnt = vfsmnt->mnt_parent; | 1813 | vfsmnt = vfsmnt->mnt_parent; |
1802 | spin_unlock(&vfsmount_lock); | ||
1803 | continue; | 1814 | continue; |
1804 | } | 1815 | } |
1805 | parent = dentry->d_parent; | 1816 | parent = dentry->d_parent; |
1806 | prefetch(parent); | 1817 | prefetch(parent); |
1807 | namelen = dentry->d_name.len; | 1818 | if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) || |
1808 | buflen -= namelen + 1; | 1819 | (prepend(&end, &buflen, "/", 1) != 0)) |
1809 | if (buflen < 0) | ||
1810 | goto Elong; | 1820 | goto Elong; |
1811 | end -= namelen; | ||
1812 | memcpy(end, dentry->d_name.name, namelen); | ||
1813 | *--end = '/'; | ||
1814 | retval = end; | 1821 | retval = end; |
1815 | dentry = parent; | 1822 | dentry = parent; |
1816 | } | 1823 | } |
1817 | 1824 | ||
1825 | out: | ||
1826 | spin_unlock(&vfsmount_lock); | ||
1818 | return retval; | 1827 | return retval; |
1819 | 1828 | ||
1820 | global_root: | 1829 | global_root: |
1821 | namelen = dentry->d_name.len; | 1830 | retval += 1; /* hit the slash */ |
1822 | buflen -= namelen; | 1831 | if (prepend_name(&retval, &buflen, &dentry->d_name) != 0) |
1823 | if (buflen < 0) | ||
1824 | goto Elong; | 1832 | goto Elong; |
1825 | retval -= namelen-1; /* hit the slash */ | 1833 | root->mnt = vfsmnt; |
1826 | memcpy(retval, dentry->d_name.name, namelen); | 1834 | root->dentry = dentry; |
1827 | return retval; | 1835 | goto out; |
1836 | |||
1828 | Elong: | 1837 | Elong: |
1829 | return ERR_PTR(-ENAMETOOLONG); | 1838 | retval = ERR_PTR(-ENAMETOOLONG); |
1839 | goto out; | ||
1830 | } | 1840 | } |
1831 | 1841 | ||
1832 | /** | 1842 | /** |
@@ -1840,12 +1850,13 @@ Elong: | |||
1840 | * | 1850 | * |
1841 | * Returns the buffer or an error code if the path was too long. | 1851 | * Returns the buffer or an error code if the path was too long. |
1842 | * | 1852 | * |
1843 | * "buflen" should be positive. Caller holds the dcache_lock. | 1853 | * "buflen" should be positive. |
1844 | */ | 1854 | */ |
1845 | char *d_path(struct path *path, char *buf, int buflen) | 1855 | char *d_path(const struct path *path, char *buf, int buflen) |
1846 | { | 1856 | { |
1847 | char *res; | 1857 | char *res; |
1848 | struct path root; | 1858 | struct path root; |
1859 | struct path tmp; | ||
1849 | 1860 | ||
1850 | /* | 1861 | /* |
1851 | * We have various synthetic filesystems that never get mounted. On | 1862 | * We have various synthetic filesystems that never get mounted. On |
@@ -1859,10 +1870,11 @@ char *d_path(struct path *path, char *buf, int buflen) | |||
1859 | 1870 | ||
1860 | read_lock(¤t->fs->lock); | 1871 | read_lock(¤t->fs->lock); |
1861 | root = current->fs->root; | 1872 | root = current->fs->root; |
1862 | path_get(¤t->fs->root); | 1873 | path_get(&root); |
1863 | read_unlock(¤t->fs->lock); | 1874 | read_unlock(¤t->fs->lock); |
1864 | spin_lock(&dcache_lock); | 1875 | spin_lock(&dcache_lock); |
1865 | res = __d_path(path->dentry, path->mnt, &root, buf, buflen); | 1876 | tmp = root; |
1877 | res = __d_path(path, &tmp, buf, buflen); | ||
1866 | spin_unlock(&dcache_lock); | 1878 | spin_unlock(&dcache_lock); |
1867 | path_put(&root); | 1879 | path_put(&root); |
1868 | return res; | 1880 | return res; |
@@ -1890,6 +1902,43 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen, | |||
1890 | } | 1902 | } |
1891 | 1903 | ||
1892 | /* | 1904 | /* |
1905 | * Write full pathname from the root of the filesystem into the buffer. | ||
1906 | */ | ||
1907 | char *dentry_path(struct dentry *dentry, char *buf, int buflen) | ||
1908 | { | ||
1909 | char *end = buf + buflen; | ||
1910 | char *retval; | ||
1911 | |||
1912 | spin_lock(&dcache_lock); | ||
1913 | prepend(&end, &buflen, "\0", 1); | ||
1914 | if (!IS_ROOT(dentry) && d_unhashed(dentry) && | ||
1915 | (prepend(&end, &buflen, "//deleted", 9) != 0)) | ||
1916 | goto Elong; | ||
1917 | if (buflen < 1) | ||
1918 | goto Elong; | ||
1919 | /* Get '/' right */ | ||
1920 | retval = end-1; | ||
1921 | *retval = '/'; | ||
1922 | |||
1923 | while (!IS_ROOT(dentry)) { | ||
1924 | struct dentry *parent = dentry->d_parent; | ||
1925 | |||
1926 | prefetch(parent); | ||
1927 | if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) || | ||
1928 | (prepend(&end, &buflen, "/", 1) != 0)) | ||
1929 | goto Elong; | ||
1930 | |||
1931 | retval = end; | ||
1932 | dentry = parent; | ||
1933 | } | ||
1934 | spin_unlock(&dcache_lock); | ||
1935 | return retval; | ||
1936 | Elong: | ||
1937 | spin_unlock(&dcache_lock); | ||
1938 | return ERR_PTR(-ENAMETOOLONG); | ||
1939 | } | ||
1940 | |||
1941 | /* | ||
1893 | * NOTE! The user-level library version returns a | 1942 | * NOTE! The user-level library version returns a |
1894 | * character pointer. The kernel system call just | 1943 | * character pointer. The kernel system call just |
1895 | * returns the length of the buffer filled (which | 1944 | * returns the length of the buffer filled (which |
@@ -1918,19 +1967,20 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) | |||
1918 | 1967 | ||
1919 | read_lock(¤t->fs->lock); | 1968 | read_lock(¤t->fs->lock); |
1920 | pwd = current->fs->pwd; | 1969 | pwd = current->fs->pwd; |
1921 | path_get(¤t->fs->pwd); | 1970 | path_get(&pwd); |
1922 | root = current->fs->root; | 1971 | root = current->fs->root; |
1923 | path_get(¤t->fs->root); | 1972 | path_get(&root); |
1924 | read_unlock(¤t->fs->lock); | 1973 | read_unlock(¤t->fs->lock); |
1925 | 1974 | ||
1926 | error = -ENOENT; | 1975 | error = -ENOENT; |
1927 | /* Has the current directory has been unlinked? */ | 1976 | /* Has the current directory has been unlinked? */ |
1928 | spin_lock(&dcache_lock); | 1977 | spin_lock(&dcache_lock); |
1929 | if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) { | 1978 | if (IS_ROOT(pwd.dentry) || !d_unhashed(pwd.dentry)) { |
1930 | unsigned long len; | 1979 | unsigned long len; |
1980 | struct path tmp = root; | ||
1931 | char * cwd; | 1981 | char * cwd; |
1932 | 1982 | ||
1933 | cwd = __d_path(pwd.dentry, pwd.mnt, &root, page, PAGE_SIZE); | 1983 | cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE); |
1934 | spin_unlock(&dcache_lock); | 1984 | spin_unlock(&dcache_lock); |
1935 | 1985 | ||
1936 | error = PTR_ERR(cwd); | 1986 | error = PTR_ERR(cwd); |