aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/dcache.c150
1 files changed, 80 insertions, 70 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index d68631f18df1..b5f613932912 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1739,45 +1739,41 @@ shouldnt_be_hashed:
1739 * @rootmnt: vfsmnt to which the root dentry belongs 1739 * @rootmnt: vfsmnt to which the root dentry belongs
1740 * @buffer: buffer to return value in 1740 * @buffer: buffer to return value in
1741 * @buflen: buffer length 1741 * @buflen: buffer length
1742 * @fail_deleted: what to return for deleted files
1742 * 1743 *
1743 * Convert a dentry into an ASCII path name. If the entry has been deleted 1744 * Convert a dentry into an ASCII path name. If the entry has been deleted,
1744 * the string " (deleted)" is appended. Note that this is ambiguous. 1745 * then if @fail_deleted is true, ERR_PTR(-ENOENT) is returned. Otherwise,
1746 * the the string " (deleted)" is appended. Note that this is ambiguous.
1745 * 1747 *
1746 * Returns the buffer or an error code if the path was too long. 1748 * Returns the buffer or an error code.
1747 *
1748 * "buflen" should be positive. Caller holds the dcache_lock.
1749 */ 1749 */
1750static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, 1750static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
1751 struct dentry *root, struct vfsmount *rootmnt, 1751 struct dentry *root, struct vfsmount *rootmnt,
1752 char *buffer, int buflen) 1752 char *buffer, int buflen, int fail_deleted)
1753{ 1753{
1754 char * end = buffer+buflen; 1754 int namelen, is_slash;
1755 char * retval; 1755
1756 int namelen; 1756 if (buflen < 2)
1757 return ERR_PTR(-ENAMETOOLONG);
1758 buffer += --buflen;
1759 *buffer = '\0';
1757 1760
1758 *--end = '\0'; 1761 spin_lock(&dcache_lock);
1759 buflen--;
1760 if (!IS_ROOT(dentry) && d_unhashed(dentry)) { 1762 if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
1761 buflen -= 10; 1763 if (fail_deleted) {
1762 end -= 10; 1764 buffer = ERR_PTR(-ENOENT);
1763 if (buflen < 0) 1765 goto out;
1766 }
1767 if (buflen < 10)
1764 goto Elong; 1768 goto Elong;
1765 memcpy(end, " (deleted)", 10); 1769 buflen -= 10;
1770 buffer -= 10;
1771 memcpy(buffer, " (deleted)", 10);
1766 } 1772 }
1767 1773 while (dentry != root || vfsmnt != rootmnt) {
1768 if (buflen < 1)
1769 goto Elong;
1770 /* Get '/' right */
1771 retval = end-1;
1772 *retval = '/';
1773
1774 for (;;) {
1775 struct dentry * parent; 1774 struct dentry * parent;
1776 1775
1777 if (dentry == root && vfsmnt == rootmnt)
1778 break;
1779 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { 1776 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
1780 /* Global root? */
1781 spin_lock(&vfsmount_lock); 1777 spin_lock(&vfsmount_lock);
1782 if (vfsmnt->mnt_parent == vfsmnt) { 1778 if (vfsmnt->mnt_parent == vfsmnt) {
1783 spin_unlock(&vfsmount_lock); 1779 spin_unlock(&vfsmount_lock);
@@ -1791,33 +1787,60 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
1791 parent = dentry->d_parent; 1787 parent = dentry->d_parent;
1792 prefetch(parent); 1788 prefetch(parent);
1793 namelen = dentry->d_name.len; 1789 namelen = dentry->d_name.len;
1794 buflen -= namelen + 1; 1790 if (buflen <= namelen)
1795 if (buflen < 0)
1796 goto Elong; 1791 goto Elong;
1797 end -= namelen; 1792 buflen -= namelen + 1;
1798 memcpy(end, dentry->d_name.name, namelen); 1793 buffer -= namelen;
1799 *--end = '/'; 1794 memcpy(buffer, dentry->d_name.name, namelen);
1800 retval = end; 1795 *--buffer = '/';
1801 dentry = parent; 1796 dentry = parent;
1802 } 1797 }
1798 /* Get '/' right */
1799 if (*buffer != '/')
1800 *--buffer = '/';
1803 1801
1804 return retval; 1802out:
1803 spin_unlock(&dcache_lock);
1804 return buffer;
1805 1805
1806global_root: 1806global_root:
1807 /*
1808 * We went past the (vfsmount, dentry) we were looking for and have
1809 * either hit a root dentry, a lazily unmounted dentry, an
1810 * unconnected dentry, or the file is on a pseudo filesystem.
1811 */
1807 namelen = dentry->d_name.len; 1812 namelen = dentry->d_name.len;
1808 buflen -= namelen; 1813 is_slash = (namelen == 1 && *dentry->d_name.name == '/');
1809 if (buflen < 0) 1814 if (is_slash || (dentry->d_sb->s_flags & MS_NOUSER)) {
1815 /*
1816 * Make sure we won't return a pathname starting with '/'.
1817 *
1818 * Historically, we also glue together the root dentry and
1819 * remaining name for pseudo filesystems like pipefs, which
1820 * have the MS_NOUSER flag set. This results in pathnames
1821 * like "pipe:[439336]".
1822 */
1823 if (*buffer == '/') {
1824 buffer++;
1825 buflen++;
1826 }
1827 if (is_slash)
1828 goto out;
1829 }
1830 if (buflen < namelen)
1810 goto Elong; 1831 goto Elong;
1811 retval -= namelen-1; /* hit the slash */ 1832 buffer -= namelen;
1812 memcpy(retval, dentry->d_name.name, namelen); 1833 memcpy(buffer, dentry->d_name.name, namelen);
1813 return retval; 1834 goto out;
1835
1814Elong: 1836Elong:
1815 return ERR_PTR(-ENAMETOOLONG); 1837 buffer = ERR_PTR(-ENAMETOOLONG);
1838 goto out;
1816} 1839}
1817 1840
1818/* write full pathname into buffer and return start of pathname */ 1841/* write full pathname into buffer and return start of pathname */
1819char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, 1842char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
1820 char *buf, int buflen) 1843 int buflen)
1821{ 1844{
1822 char *res; 1845 char *res;
1823 struct vfsmount *rootmnt; 1846 struct vfsmount *rootmnt;
@@ -1827,9 +1850,7 @@ char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
1827 rootmnt = mntget(current->fs->rootmnt); 1850 rootmnt = mntget(current->fs->rootmnt);
1828 root = dget(current->fs->root); 1851 root = dget(current->fs->root);
1829 read_unlock(&current->fs->lock); 1852 read_unlock(&current->fs->lock);
1830 spin_lock(&dcache_lock); 1853 res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0);
1831 res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen);
1832 spin_unlock(&dcache_lock);
1833 dput(root); 1854 dput(root);
1834 mntput(rootmnt); 1855 mntput(rootmnt);
1835 return res; 1856 return res;
@@ -1855,10 +1876,10 @@ char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
1855 */ 1876 */
1856asmlinkage long sys_getcwd(char __user *buf, unsigned long size) 1877asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
1857{ 1878{
1858 int error; 1879 int error, len;
1859 struct vfsmount *pwdmnt, *rootmnt; 1880 struct vfsmount *pwdmnt, *rootmnt;
1860 struct dentry *pwd, *root; 1881 struct dentry *pwd, *root;
1861 char *page = (char *) __get_free_page(GFP_USER); 1882 char *page = (char *) __get_free_page(GFP_USER), *cwd;
1862 1883
1863 if (!page) 1884 if (!page)
1864 return -ENOMEM; 1885 return -ENOMEM;
@@ -1870,29 +1891,18 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
1870 root = dget(current->fs->root); 1891 root = dget(current->fs->root);
1871 read_unlock(&current->fs->lock); 1892 read_unlock(&current->fs->lock);
1872 1893
1873 error = -ENOENT; 1894 cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1);
1874 /* Has the current directory has been unlinked? */ 1895 error = PTR_ERR(cwd);
1875 spin_lock(&dcache_lock); 1896 if (IS_ERR(cwd))
1876 if (pwd->d_parent == pwd || !d_unhashed(pwd)) { 1897 goto out;
1877 unsigned long len;
1878 char * cwd;
1879
1880 cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE);
1881 spin_unlock(&dcache_lock);
1882
1883 error = PTR_ERR(cwd);
1884 if (IS_ERR(cwd))
1885 goto out;
1886 1898
1887 error = -ERANGE; 1899 error = -ERANGE;
1888 len = PAGE_SIZE + page - cwd; 1900 len = PAGE_SIZE + page - cwd;
1889 if (len <= size) { 1901 if (len <= size) {
1890 error = len; 1902 error = len;
1891 if (copy_to_user(buf, cwd, len)) 1903 if (copy_to_user(buf, cwd, len))
1892 error = -EFAULT; 1904 error = -EFAULT;
1893 } 1905 }
1894 } else
1895 spin_unlock(&dcache_lock);
1896 1906
1897out: 1907out:
1898 dput(pwd); 1908 dput(pwd);