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