diff options
Diffstat (limited to 'fs/dcache.c')
| -rw-r--r-- | fs/dcache.c | 114 |
1 files changed, 82 insertions, 32 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 43455776711e..3ee588d5f585 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -1746,12 +1746,21 @@ shouldnt_be_hashed: | |||
| 1746 | goto shouldnt_be_hashed; | 1746 | goto shouldnt_be_hashed; |
| 1747 | } | 1747 | } |
| 1748 | 1748 | ||
| 1749 | static int prepend(char **buffer, int *buflen, const char *str, | ||
| 1750 | 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 | |||
| 1749 | /** | 1760 | /** |
| 1750 | * d_path - return the path of a dentry | 1761 | * d_path - return the path of a dentry |
| 1751 | * @dentry: dentry to report | 1762 | * @path: the dentry/vfsmount to report |
| 1752 | * @vfsmnt: vfsmnt to which the dentry belongs | 1763 | * @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 | 1764 | * @buffer: buffer to return value in |
| 1756 | * @buflen: buffer length | 1765 | * @buflen: buffer length |
| 1757 | * | 1766 | * |
| @@ -1761,23 +1770,22 @@ shouldnt_be_hashed: | |||
| 1761 | * Returns the buffer or an error code if the path was too long. | 1770 | * Returns the buffer or an error code if the path was too long. |
| 1762 | * | 1771 | * |
| 1763 | * "buflen" should be positive. Caller holds the dcache_lock. | 1772 | * "buflen" should be positive. Caller holds the dcache_lock. |
| 1773 | * | ||
| 1774 | * If path is not reachable from the supplied root, then the value of | ||
| 1775 | * root is changed (without modifying refcounts). | ||
| 1764 | */ | 1776 | */ |
| 1765 | static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, | 1777 | char *__d_path(const struct path *path, struct path *root, |
| 1766 | struct path *root, char *buffer, int buflen) | 1778 | char *buffer, int buflen) |
| 1767 | { | 1779 | { |
| 1780 | struct dentry *dentry = path->dentry; | ||
| 1781 | struct vfsmount *vfsmnt = path->mnt; | ||
| 1768 | char * end = buffer+buflen; | 1782 | char * end = buffer+buflen; |
| 1769 | char * retval; | 1783 | char * retval; |
| 1770 | int namelen; | 1784 | |
| 1771 | 1785 | prepend(&end, &buflen, "\0", 1); | |
| 1772 | *--end = '\0'; | 1786 | if (!IS_ROOT(dentry) && d_unhashed(dentry) && |
| 1773 | buflen--; | 1787 | (prepend(&end, &buflen, " (deleted)", 10) != 0)) |
| 1774 | if (!IS_ROOT(dentry) && d_unhashed(dentry)) { | ||
| 1775 | buflen -= 10; | ||
| 1776 | end -= 10; | ||
| 1777 | if (buflen < 0) | ||
| 1778 | goto Elong; | 1788 | goto Elong; |
| 1779 | memcpy(end, " (deleted)", 10); | ||
| 1780 | } | ||
| 1781 | 1789 | ||
| 1782 | if (buflen < 1) | 1790 | if (buflen < 1) |
| 1783 | goto Elong; | 1791 | goto Elong; |
| @@ -1804,13 +1812,10 @@ static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, | |||
| 1804 | } | 1812 | } |
| 1805 | parent = dentry->d_parent; | 1813 | parent = dentry->d_parent; |
| 1806 | prefetch(parent); | 1814 | prefetch(parent); |
| 1807 | namelen = dentry->d_name.len; | 1815 | if ((prepend(&end, &buflen, dentry->d_name.name, |
| 1808 | buflen -= namelen + 1; | 1816 | dentry->d_name.len) != 0) || |
| 1809 | if (buflen < 0) | 1817 | (prepend(&end, &buflen, "/", 1) != 0)) |
| 1810 | goto Elong; | 1818 | goto Elong; |
| 1811 | end -= namelen; | ||
| 1812 | memcpy(end, dentry->d_name.name, namelen); | ||
| 1813 | *--end = '/'; | ||
| 1814 | retval = end; | 1819 | retval = end; |
| 1815 | dentry = parent; | 1820 | dentry = parent; |
| 1816 | } | 1821 | } |
| @@ -1818,12 +1823,12 @@ static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, | |||
| 1818 | return retval; | 1823 | return retval; |
| 1819 | 1824 | ||
| 1820 | global_root: | 1825 | global_root: |
| 1821 | namelen = dentry->d_name.len; | 1826 | retval += 1; /* hit the slash */ |
| 1822 | buflen -= namelen; | 1827 | if (prepend(&retval, &buflen, dentry->d_name.name, |
| 1823 | if (buflen < 0) | 1828 | dentry->d_name.len) != 0) |
| 1824 | goto Elong; | 1829 | goto Elong; |
| 1825 | retval -= namelen-1; /* hit the slash */ | 1830 | root->mnt = vfsmnt; |
| 1826 | memcpy(retval, dentry->d_name.name, namelen); | 1831 | root->dentry = dentry; |
| 1827 | return retval; | 1832 | return retval; |
| 1828 | Elong: | 1833 | Elong: |
| 1829 | return ERR_PTR(-ENAMETOOLONG); | 1834 | return ERR_PTR(-ENAMETOOLONG); |
| @@ -1846,6 +1851,7 @@ char *d_path(struct path *path, char *buf, int buflen) | |||
| 1846 | { | 1851 | { |
| 1847 | char *res; | 1852 | char *res; |
| 1848 | struct path root; | 1853 | struct path root; |
| 1854 | struct path tmp; | ||
| 1849 | 1855 | ||
| 1850 | /* | 1856 | /* |
| 1851 | * We have various synthetic filesystems that never get mounted. On | 1857 | * We have various synthetic filesystems that never get mounted. On |
| @@ -1859,10 +1865,11 @@ char *d_path(struct path *path, char *buf, int buflen) | |||
| 1859 | 1865 | ||
| 1860 | read_lock(¤t->fs->lock); | 1866 | read_lock(¤t->fs->lock); |
| 1861 | root = current->fs->root; | 1867 | root = current->fs->root; |
| 1862 | path_get(¤t->fs->root); | 1868 | path_get(&root); |
| 1863 | read_unlock(¤t->fs->lock); | 1869 | read_unlock(¤t->fs->lock); |
| 1864 | spin_lock(&dcache_lock); | 1870 | spin_lock(&dcache_lock); |
| 1865 | res = __d_path(path->dentry, path->mnt, &root, buf, buflen); | 1871 | tmp = root; |
| 1872 | res = __d_path(path, &tmp, buf, buflen); | ||
| 1866 | spin_unlock(&dcache_lock); | 1873 | spin_unlock(&dcache_lock); |
| 1867 | path_put(&root); | 1874 | path_put(&root); |
| 1868 | return res; | 1875 | return res; |
| @@ -1890,6 +1897,48 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen, | |||
| 1890 | } | 1897 | } |
| 1891 | 1898 | ||
| 1892 | /* | 1899 | /* |
| 1900 | * Write full pathname from the root of the filesystem into the buffer. | ||
| 1901 | */ | ||
| 1902 | char *dentry_path(struct dentry *dentry, char *buf, int buflen) | ||
| 1903 | { | ||
| 1904 | char *end = buf + buflen; | ||
| 1905 | char *retval; | ||
| 1906 | |||
| 1907 | spin_lock(&dcache_lock); | ||
| 1908 | prepend(&end, &buflen, "\0", 1); | ||
| 1909 | if (!IS_ROOT(dentry) && d_unhashed(dentry) && | ||
| 1910 | (prepend(&end, &buflen, "//deleted", 9) != 0)) | ||
| 1911 | goto Elong; | ||
| 1912 | if (buflen < 1) | ||
| 1913 | goto Elong; | ||
| 1914 | /* Get '/' right */ | ||
| 1915 | retval = end-1; | ||
| 1916 | *retval = '/'; | ||
| 1917 | |||
| 1918 | for (;;) { | ||
| 1919 | struct dentry *parent; | ||
| 1920 | if (IS_ROOT(dentry)) | ||
| 1921 | break; | ||
| 1922 | |||
| 1923 | parent = dentry->d_parent; | ||
| 1924 | prefetch(parent); | ||
| 1925 | |||
| 1926 | if ((prepend(&end, &buflen, dentry->d_name.name, | ||
| 1927 | dentry->d_name.len) != 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,9 +1967,9 @@ 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; |
| @@ -1928,9 +1977,10 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) | |||
| 1928 | spin_lock(&dcache_lock); | 1977 | spin_lock(&dcache_lock); |
| 1929 | if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) { | 1978 | if (pwd.dentry->d_parent == 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); |
