diff options
Diffstat (limited to 'fs/dcache.c')
| -rw-r--r-- | fs/dcache.c | 68 |
1 files changed, 34 insertions, 34 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 3ee588d5f585..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,11 +1745,9 @@ 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; | ||
| 1747 | } | 1748 | } |
| 1748 | 1749 | ||
| 1749 | static int prepend(char **buffer, int *buflen, const char *str, | 1750 | static int prepend(char **buffer, int *buflen, const char *str, int namelen) |
| 1750 | int namelen) | ||
| 1751 | { | 1751 | { |
| 1752 | *buflen -= namelen; | 1752 | *buflen -= namelen; |
| 1753 | if (*buflen < 0) | 1753 | if (*buflen < 0) |
| @@ -1757,8 +1757,13 @@ static int prepend(char **buffer, int *buflen, const char *str, | |||
| 1757 | return 0; | 1757 | return 0; |
| 1758 | } | 1758 | } |
| 1759 | 1759 | ||
| 1760 | static int prepend_name(char **buffer, int *buflen, struct qstr *name) | ||
| 1761 | { | ||
| 1762 | return prepend(buffer, buflen, name->name, name->len); | ||
| 1763 | } | ||
| 1764 | |||
| 1760 | /** | 1765 | /** |
| 1761 | * d_path - return the path of a dentry | 1766 | * __d_path - return the path of a dentry |
| 1762 | * @path: the dentry/vfsmount to report | 1767 | * @path: the dentry/vfsmount to report |
| 1763 | * @root: root vfsmnt/dentry (may be modified by this function) | 1768 | * @root: root vfsmnt/dentry (may be modified by this function) |
| 1764 | * @buffer: buffer to return value in | 1769 | * @buffer: buffer to return value in |
| @@ -1779,9 +1784,10 @@ char *__d_path(const struct path *path, struct path *root, | |||
| 1779 | { | 1784 | { |
| 1780 | struct dentry *dentry = path->dentry; | 1785 | struct dentry *dentry = path->dentry; |
| 1781 | struct vfsmount *vfsmnt = path->mnt; | 1786 | struct vfsmount *vfsmnt = path->mnt; |
| 1782 | char * end = buffer+buflen; | 1787 | char *end = buffer + buflen; |
| 1783 | char * retval; | 1788 | char *retval; |
| 1784 | 1789 | ||
| 1790 | spin_lock(&vfsmount_lock); | ||
| 1785 | prepend(&end, &buflen, "\0", 1); | 1791 | prepend(&end, &buflen, "\0", 1); |
| 1786 | if (!IS_ROOT(dentry) && d_unhashed(dentry) && | 1792 | if (!IS_ROOT(dentry) && d_unhashed(dentry) && |
| 1787 | (prepend(&end, &buflen, " (deleted)", 10) != 0)) | 1793 | (prepend(&end, &buflen, " (deleted)", 10) != 0)) |
| @@ -1800,38 +1806,37 @@ char *__d_path(const struct path *path, struct path *root, | |||
| 1800 | break; | 1806 | break; |
| 1801 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { | 1807 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { |
| 1802 | /* Global root? */ | 1808 | /* Global root? */ |
| 1803 | spin_lock(&vfsmount_lock); | ||
| 1804 | if (vfsmnt->mnt_parent == vfsmnt) { | 1809 | if (vfsmnt->mnt_parent == vfsmnt) { |
| 1805 | spin_unlock(&vfsmount_lock); | ||
| 1806 | goto global_root; | 1810 | goto global_root; |
| 1807 | } | 1811 | } |
| 1808 | dentry = vfsmnt->mnt_mountpoint; | 1812 | dentry = vfsmnt->mnt_mountpoint; |
| 1809 | vfsmnt = vfsmnt->mnt_parent; | 1813 | vfsmnt = vfsmnt->mnt_parent; |
| 1810 | spin_unlock(&vfsmount_lock); | ||
| 1811 | continue; | 1814 | continue; |
| 1812 | } | 1815 | } |
| 1813 | parent = dentry->d_parent; | 1816 | parent = dentry->d_parent; |
| 1814 | prefetch(parent); | 1817 | prefetch(parent); |
| 1815 | if ((prepend(&end, &buflen, dentry->d_name.name, | 1818 | if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) || |
| 1816 | dentry->d_name.len) != 0) || | ||
| 1817 | (prepend(&end, &buflen, "/", 1) != 0)) | 1819 | (prepend(&end, &buflen, "/", 1) != 0)) |
| 1818 | goto Elong; | 1820 | goto Elong; |
| 1819 | retval = end; | 1821 | retval = end; |
| 1820 | dentry = parent; | 1822 | dentry = parent; |
| 1821 | } | 1823 | } |
| 1822 | 1824 | ||
| 1825 | out: | ||
| 1826 | spin_unlock(&vfsmount_lock); | ||
| 1823 | return retval; | 1827 | return retval; |
| 1824 | 1828 | ||
| 1825 | global_root: | 1829 | global_root: |
| 1826 | retval += 1; /* hit the slash */ | 1830 | retval += 1; /* hit the slash */ |
| 1827 | if (prepend(&retval, &buflen, dentry->d_name.name, | 1831 | if (prepend_name(&retval, &buflen, &dentry->d_name) != 0) |
| 1828 | dentry->d_name.len) != 0) | ||
| 1829 | goto Elong; | 1832 | goto Elong; |
| 1830 | root->mnt = vfsmnt; | 1833 | root->mnt = vfsmnt; |
| 1831 | root->dentry = dentry; | 1834 | root->dentry = dentry; |
| 1832 | return retval; | 1835 | goto out; |
| 1836 | |||
| 1833 | Elong: | 1837 | Elong: |
| 1834 | return ERR_PTR(-ENAMETOOLONG); | 1838 | retval = ERR_PTR(-ENAMETOOLONG); |
| 1839 | goto out; | ||
| 1835 | } | 1840 | } |
| 1836 | 1841 | ||
| 1837 | /** | 1842 | /** |
| @@ -1845,9 +1850,9 @@ Elong: | |||
| 1845 | * | 1850 | * |
| 1846 | * 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. |
| 1847 | * | 1852 | * |
| 1848 | * "buflen" should be positive. Caller holds the dcache_lock. | 1853 | * "buflen" should be positive. |
| 1849 | */ | 1854 | */ |
| 1850 | char *d_path(struct path *path, char *buf, int buflen) | 1855 | char *d_path(const struct path *path, char *buf, int buflen) |
| 1851 | { | 1856 | { |
| 1852 | char *res; | 1857 | char *res; |
| 1853 | struct path root; | 1858 | struct path root; |
| @@ -1915,16 +1920,11 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen) | |||
| 1915 | retval = end-1; | 1920 | retval = end-1; |
| 1916 | *retval = '/'; | 1921 | *retval = '/'; |
| 1917 | 1922 | ||
| 1918 | for (;;) { | 1923 | while (!IS_ROOT(dentry)) { |
| 1919 | struct dentry *parent; | 1924 | struct dentry *parent = dentry->d_parent; |
| 1920 | if (IS_ROOT(dentry)) | ||
| 1921 | break; | ||
| 1922 | 1925 | ||
| 1923 | parent = dentry->d_parent; | ||
| 1924 | prefetch(parent); | 1926 | prefetch(parent); |
| 1925 | 1927 | if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) || | |
| 1926 | if ((prepend(&end, &buflen, dentry->d_name.name, | ||
| 1927 | dentry->d_name.len) != 0) || | ||
| 1928 | (prepend(&end, &buflen, "/", 1) != 0)) | 1928 | (prepend(&end, &buflen, "/", 1) != 0)) |
| 1929 | goto Elong; | 1929 | goto Elong; |
| 1930 | 1930 | ||
| @@ -1975,7 +1975,7 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) | |||
| 1975 | error = -ENOENT; | 1975 | error = -ENOENT; |
| 1976 | /* Has the current directory has been unlinked? */ | 1976 | /* Has the current directory has been unlinked? */ |
| 1977 | spin_lock(&dcache_lock); | 1977 | spin_lock(&dcache_lock); |
| 1978 | if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) { | 1978 | if (IS_ROOT(pwd.dentry) || !d_unhashed(pwd.dentry)) { |
| 1979 | unsigned long len; | 1979 | unsigned long len; |
| 1980 | struct path tmp = root; | 1980 | struct path tmp = root; |
| 1981 | char * cwd; | 1981 | char * cwd; |
