diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 298 |
1 files changed, 203 insertions, 95 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 86d4db15473e..83293be48149 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -536,7 +536,7 @@ restart: | |||
536 | */ | 536 | */ |
537 | static void prune_dcache(int count) | 537 | static void prune_dcache(int count) |
538 | { | 538 | { |
539 | struct super_block *sb, *n; | 539 | struct super_block *sb, *p = NULL; |
540 | int w_count; | 540 | int w_count; |
541 | int unused = dentry_stat.nr_unused; | 541 | int unused = dentry_stat.nr_unused; |
542 | int prune_ratio; | 542 | int prune_ratio; |
@@ -550,7 +550,7 @@ static void prune_dcache(int count) | |||
550 | else | 550 | else |
551 | prune_ratio = unused / count; | 551 | prune_ratio = unused / count; |
552 | spin_lock(&sb_lock); | 552 | spin_lock(&sb_lock); |
553 | list_for_each_entry_safe(sb, n, &super_blocks, s_list) { | 553 | list_for_each_entry(sb, &super_blocks, s_list) { |
554 | if (list_empty(&sb->s_instances)) | 554 | if (list_empty(&sb->s_instances)) |
555 | continue; | 555 | continue; |
556 | if (sb->s_nr_dentry_unused == 0) | 556 | if (sb->s_nr_dentry_unused == 0) |
@@ -590,14 +590,16 @@ static void prune_dcache(int count) | |||
590 | up_read(&sb->s_umount); | 590 | up_read(&sb->s_umount); |
591 | } | 591 | } |
592 | spin_lock(&sb_lock); | 592 | spin_lock(&sb_lock); |
593 | /* lock was dropped, must reset next */ | 593 | if (p) |
594 | list_safe_reset_next(sb, n, s_list); | 594 | __put_super(p); |
595 | count -= pruned; | 595 | count -= pruned; |
596 | __put_super(sb); | 596 | p = sb; |
597 | /* more work left to do? */ | 597 | /* more work left to do? */ |
598 | if (count <= 0) | 598 | if (count <= 0) |
599 | break; | 599 | break; |
600 | } | 600 | } |
601 | if (p) | ||
602 | __put_super(p); | ||
601 | spin_unlock(&sb_lock); | 603 | spin_unlock(&sb_lock); |
602 | spin_unlock(&dcache_lock); | 604 | spin_unlock(&dcache_lock); |
603 | } | 605 | } |
@@ -1330,31 +1332,13 @@ EXPORT_SYMBOL(d_add_ci); | |||
1330 | * d_lookup - search for a dentry | 1332 | * d_lookup - search for a dentry |
1331 | * @parent: parent dentry | 1333 | * @parent: parent dentry |
1332 | * @name: qstr of name we wish to find | 1334 | * @name: qstr of name we wish to find |
1335 | * Returns: dentry, or NULL | ||
1333 | * | 1336 | * |
1334 | * Searches the children of the parent dentry for the name in question. If | 1337 | * d_lookup searches the children of the parent dentry for the name in |
1335 | * the dentry is found its reference count is incremented and the dentry | 1338 | * question. If the dentry is found its reference count is incremented and the |
1336 | * is returned. The caller must use dput to free the entry when it has | 1339 | * dentry is returned. The caller must use dput to free the entry when it has |
1337 | * finished using it. %NULL is returned on failure. | 1340 | * finished using it. %NULL is returned if the dentry does not exist. |
1338 | * | ||
1339 | * __d_lookup is dcache_lock free. The hash list is protected using RCU. | ||
1340 | * Memory barriers are used while updating and doing lockless traversal. | ||
1341 | * To avoid races with d_move while rename is happening, d_lock is used. | ||
1342 | * | ||
1343 | * Overflows in memcmp(), while d_move, are avoided by keeping the length | ||
1344 | * and name pointer in one structure pointed by d_qstr. | ||
1345 | * | ||
1346 | * rcu_read_lock() and rcu_read_unlock() are used to disable preemption while | ||
1347 | * lookup is going on. | ||
1348 | * | ||
1349 | * The dentry unused LRU is not updated even if lookup finds the required dentry | ||
1350 | * in there. It is updated in places such as prune_dcache, shrink_dcache_sb, | ||
1351 | * select_parent and __dget_locked. This laziness saves lookup from dcache_lock | ||
1352 | * acquisition. | ||
1353 | * | ||
1354 | * d_lookup() is protected against the concurrent renames in some unrelated | ||
1355 | * directory using the seqlockt_t rename_lock. | ||
1356 | */ | 1341 | */ |
1357 | |||
1358 | struct dentry * d_lookup(struct dentry * parent, struct qstr * name) | 1342 | struct dentry * d_lookup(struct dentry * parent, struct qstr * name) |
1359 | { | 1343 | { |
1360 | struct dentry * dentry = NULL; | 1344 | struct dentry * dentry = NULL; |
@@ -1370,6 +1354,21 @@ struct dentry * d_lookup(struct dentry * parent, struct qstr * name) | |||
1370 | } | 1354 | } |
1371 | EXPORT_SYMBOL(d_lookup); | 1355 | EXPORT_SYMBOL(d_lookup); |
1372 | 1356 | ||
1357 | /* | ||
1358 | * __d_lookup - search for a dentry (racy) | ||
1359 | * @parent: parent dentry | ||
1360 | * @name: qstr of name we wish to find | ||
1361 | * Returns: dentry, or NULL | ||
1362 | * | ||
1363 | * __d_lookup is like d_lookup, however it may (rarely) return a | ||
1364 | * false-negative result due to unrelated rename activity. | ||
1365 | * | ||
1366 | * __d_lookup is slightly faster by avoiding rename_lock read seqlock, | ||
1367 | * however it must be used carefully, eg. with a following d_lookup in | ||
1368 | * the case of failure. | ||
1369 | * | ||
1370 | * __d_lookup callers must be commented. | ||
1371 | */ | ||
1373 | struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) | 1372 | struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) |
1374 | { | 1373 | { |
1375 | unsigned int len = name->len; | 1374 | unsigned int len = name->len; |
@@ -1380,6 +1379,19 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) | |||
1380 | struct hlist_node *node; | 1379 | struct hlist_node *node; |
1381 | struct dentry *dentry; | 1380 | struct dentry *dentry; |
1382 | 1381 | ||
1382 | /* | ||
1383 | * The hash list is protected using RCU. | ||
1384 | * | ||
1385 | * Take d_lock when comparing a candidate dentry, to avoid races | ||
1386 | * with d_move(). | ||
1387 | * | ||
1388 | * It is possible that concurrent renames can mess up our list | ||
1389 | * walk here and result in missing our dentry, resulting in the | ||
1390 | * false-negative result. d_lookup() protects against concurrent | ||
1391 | * renames using rename_lock seqlock. | ||
1392 | * | ||
1393 | * See Documentation/vfs/dcache-locking.txt for more details. | ||
1394 | */ | ||
1383 | rcu_read_lock(); | 1395 | rcu_read_lock(); |
1384 | 1396 | ||
1385 | hlist_for_each_entry_rcu(dentry, node, head, d_hash) { | 1397 | hlist_for_each_entry_rcu(dentry, node, head, d_hash) { |
@@ -1394,8 +1406,8 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) | |||
1394 | 1406 | ||
1395 | /* | 1407 | /* |
1396 | * Recheck the dentry after taking the lock - d_move may have | 1408 | * Recheck the dentry after taking the lock - d_move may have |
1397 | * changed things. Don't bother checking the hash because we're | 1409 | * changed things. Don't bother checking the hash because |
1398 | * about to compare the whole name anyway. | 1410 | * we're about to compare the whole name anyway. |
1399 | */ | 1411 | */ |
1400 | if (dentry->d_parent != parent) | 1412 | if (dentry->d_parent != parent) |
1401 | goto next; | 1413 | goto next; |
@@ -1903,48 +1915,30 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name) | |||
1903 | } | 1915 | } |
1904 | 1916 | ||
1905 | /** | 1917 | /** |
1906 | * __d_path - return the path of a dentry | 1918 | * Prepend path string to a buffer |
1919 | * | ||
1907 | * @path: the dentry/vfsmount to report | 1920 | * @path: the dentry/vfsmount to report |
1908 | * @root: root vfsmnt/dentry (may be modified by this function) | 1921 | * @root: root vfsmnt/dentry (may be modified by this function) |
1909 | * @buffer: buffer to return value in | 1922 | * @buffer: pointer to the end of the buffer |
1910 | * @buflen: buffer length | 1923 | * @buflen: pointer to buffer length |
1911 | * | ||
1912 | * Convert a dentry into an ASCII path name. If the entry has been deleted | ||
1913 | * the string " (deleted)" is appended. Note that this is ambiguous. | ||
1914 | * | ||
1915 | * Returns a pointer into the buffer or an error code if the | ||
1916 | * path was too long. | ||
1917 | * | 1924 | * |
1918 | * "buflen" should be positive. Caller holds the dcache_lock. | 1925 | * Caller holds the dcache_lock. |
1919 | * | 1926 | * |
1920 | * If path is not reachable from the supplied root, then the value of | 1927 | * If path is not reachable from the supplied root, then the value of |
1921 | * root is changed (without modifying refcounts). | 1928 | * root is changed (without modifying refcounts). |
1922 | */ | 1929 | */ |
1923 | char *__d_path(const struct path *path, struct path *root, | 1930 | static int prepend_path(const struct path *path, struct path *root, |
1924 | char *buffer, int buflen) | 1931 | char **buffer, int *buflen) |
1925 | { | 1932 | { |
1926 | struct dentry *dentry = path->dentry; | 1933 | struct dentry *dentry = path->dentry; |
1927 | struct vfsmount *vfsmnt = path->mnt; | 1934 | struct vfsmount *vfsmnt = path->mnt; |
1928 | char *end = buffer + buflen; | 1935 | bool slash = false; |
1929 | char *retval; | 1936 | int error = 0; |
1930 | |||
1931 | spin_lock(&vfsmount_lock); | ||
1932 | prepend(&end, &buflen, "\0", 1); | ||
1933 | if (d_unlinked(dentry) && | ||
1934 | (prepend(&end, &buflen, " (deleted)", 10) != 0)) | ||
1935 | goto Elong; | ||
1936 | 1937 | ||
1937 | if (buflen < 1) | 1938 | br_read_lock(vfsmount_lock); |
1938 | goto Elong; | 1939 | while (dentry != root->dentry || vfsmnt != root->mnt) { |
1939 | /* Get '/' right */ | ||
1940 | retval = end-1; | ||
1941 | *retval = '/'; | ||
1942 | |||
1943 | for (;;) { | ||
1944 | struct dentry * parent; | 1940 | struct dentry * parent; |
1945 | 1941 | ||
1946 | if (dentry == root->dentry && vfsmnt == root->mnt) | ||
1947 | break; | ||
1948 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { | 1942 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { |
1949 | /* Global root? */ | 1943 | /* Global root? */ |
1950 | if (vfsmnt->mnt_parent == vfsmnt) { | 1944 | if (vfsmnt->mnt_parent == vfsmnt) { |
@@ -1956,28 +1950,88 @@ char *__d_path(const struct path *path, struct path *root, | |||
1956 | } | 1950 | } |
1957 | parent = dentry->d_parent; | 1951 | parent = dentry->d_parent; |
1958 | prefetch(parent); | 1952 | prefetch(parent); |
1959 | if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) || | 1953 | error = prepend_name(buffer, buflen, &dentry->d_name); |
1960 | (prepend(&end, &buflen, "/", 1) != 0)) | 1954 | if (!error) |
1961 | goto Elong; | 1955 | error = prepend(buffer, buflen, "/", 1); |
1962 | retval = end; | 1956 | if (error) |
1957 | break; | ||
1958 | |||
1959 | slash = true; | ||
1963 | dentry = parent; | 1960 | dentry = parent; |
1964 | } | 1961 | } |
1965 | 1962 | ||
1966 | out: | 1963 | out: |
1967 | spin_unlock(&vfsmount_lock); | 1964 | if (!error && !slash) |
1968 | return retval; | 1965 | error = prepend(buffer, buflen, "/", 1); |
1966 | |||
1967 | br_read_unlock(vfsmount_lock); | ||
1968 | return error; | ||
1969 | 1969 | ||
1970 | global_root: | 1970 | global_root: |
1971 | retval += 1; /* hit the slash */ | 1971 | /* |
1972 | if (prepend_name(&retval, &buflen, &dentry->d_name) != 0) | 1972 | * Filesystems needing to implement special "root names" |
1973 | goto Elong; | 1973 | * should do so with ->d_dname() |
1974 | */ | ||
1975 | if (IS_ROOT(dentry) && | ||
1976 | (dentry->d_name.len != 1 || dentry->d_name.name[0] != '/')) { | ||
1977 | WARN(1, "Root dentry has weird name <%.*s>\n", | ||
1978 | (int) dentry->d_name.len, dentry->d_name.name); | ||
1979 | } | ||
1974 | root->mnt = vfsmnt; | 1980 | root->mnt = vfsmnt; |
1975 | root->dentry = dentry; | 1981 | root->dentry = dentry; |
1976 | goto out; | 1982 | goto out; |
1983 | } | ||
1977 | 1984 | ||
1978 | Elong: | 1985 | /** |
1979 | retval = ERR_PTR(-ENAMETOOLONG); | 1986 | * __d_path - return the path of a dentry |
1980 | goto out; | 1987 | * @path: the dentry/vfsmount to report |
1988 | * @root: root vfsmnt/dentry (may be modified by this function) | ||
1989 | * @buf: buffer to return value in | ||
1990 | * @buflen: buffer length | ||
1991 | * | ||
1992 | * Convert a dentry into an ASCII path name. | ||
1993 | * | ||
1994 | * Returns a pointer into the buffer or an error code if the | ||
1995 | * path was too long. | ||
1996 | * | ||
1997 | * "buflen" should be positive. Caller holds the dcache_lock. | ||
1998 | * | ||
1999 | * If path is not reachable from the supplied root, then the value of | ||
2000 | * root is changed (without modifying refcounts). | ||
2001 | */ | ||
2002 | char *__d_path(const struct path *path, struct path *root, | ||
2003 | char *buf, int buflen) | ||
2004 | { | ||
2005 | char *res = buf + buflen; | ||
2006 | int error; | ||
2007 | |||
2008 | prepend(&res, &buflen, "\0", 1); | ||
2009 | error = prepend_path(path, root, &res, &buflen); | ||
2010 | if (error) | ||
2011 | return ERR_PTR(error); | ||
2012 | |||
2013 | return res; | ||
2014 | } | ||
2015 | |||
2016 | /* | ||
2017 | * same as __d_path but appends "(deleted)" for unlinked files. | ||
2018 | */ | ||
2019 | static int path_with_deleted(const struct path *path, struct path *root, | ||
2020 | char **buf, int *buflen) | ||
2021 | { | ||
2022 | prepend(buf, buflen, "\0", 1); | ||
2023 | if (d_unlinked(path->dentry)) { | ||
2024 | int error = prepend(buf, buflen, " (deleted)", 10); | ||
2025 | if (error) | ||
2026 | return error; | ||
2027 | } | ||
2028 | |||
2029 | return prepend_path(path, root, buf, buflen); | ||
2030 | } | ||
2031 | |||
2032 | static int prepend_unreachable(char **buffer, int *buflen) | ||
2033 | { | ||
2034 | return prepend(buffer, buflen, "(unreachable)", 13); | ||
1981 | } | 2035 | } |
1982 | 2036 | ||
1983 | /** | 2037 | /** |
@@ -1998,9 +2052,10 @@ Elong: | |||
1998 | */ | 2052 | */ |
1999 | char *d_path(const struct path *path, char *buf, int buflen) | 2053 | char *d_path(const struct path *path, char *buf, int buflen) |
2000 | { | 2054 | { |
2001 | char *res; | 2055 | char *res = buf + buflen; |
2002 | struct path root; | 2056 | struct path root; |
2003 | struct path tmp; | 2057 | struct path tmp; |
2058 | int error; | ||
2004 | 2059 | ||
2005 | /* | 2060 | /* |
2006 | * We have various synthetic filesystems that never get mounted. On | 2061 | * We have various synthetic filesystems that never get mounted. On |
@@ -2012,19 +2067,51 @@ char *d_path(const struct path *path, char *buf, int buflen) | |||
2012 | if (path->dentry->d_op && path->dentry->d_op->d_dname) | 2067 | if (path->dentry->d_op && path->dentry->d_op->d_dname) |
2013 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); | 2068 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); |
2014 | 2069 | ||
2015 | read_lock(¤t->fs->lock); | 2070 | get_fs_root(current->fs, &root); |
2016 | root = current->fs->root; | ||
2017 | path_get(&root); | ||
2018 | read_unlock(¤t->fs->lock); | ||
2019 | spin_lock(&dcache_lock); | 2071 | spin_lock(&dcache_lock); |
2020 | tmp = root; | 2072 | tmp = root; |
2021 | res = __d_path(path, &tmp, buf, buflen); | 2073 | error = path_with_deleted(path, &tmp, &res, &buflen); |
2074 | if (error) | ||
2075 | res = ERR_PTR(error); | ||
2022 | spin_unlock(&dcache_lock); | 2076 | spin_unlock(&dcache_lock); |
2023 | path_put(&root); | 2077 | path_put(&root); |
2024 | return res; | 2078 | return res; |
2025 | } | 2079 | } |
2026 | EXPORT_SYMBOL(d_path); | 2080 | EXPORT_SYMBOL(d_path); |
2027 | 2081 | ||
2082 | /** | ||
2083 | * d_path_with_unreachable - return the path of a dentry | ||
2084 | * @path: path to report | ||
2085 | * @buf: buffer to return value in | ||
2086 | * @buflen: buffer length | ||
2087 | * | ||
2088 | * The difference from d_path() is that this prepends "(unreachable)" | ||
2089 | * to paths which are unreachable from the current process' root. | ||
2090 | */ | ||
2091 | char *d_path_with_unreachable(const struct path *path, char *buf, int buflen) | ||
2092 | { | ||
2093 | char *res = buf + buflen; | ||
2094 | struct path root; | ||
2095 | struct path tmp; | ||
2096 | int error; | ||
2097 | |||
2098 | if (path->dentry->d_op && path->dentry->d_op->d_dname) | ||
2099 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); | ||
2100 | |||
2101 | get_fs_root(current->fs, &root); | ||
2102 | spin_lock(&dcache_lock); | ||
2103 | tmp = root; | ||
2104 | error = path_with_deleted(path, &tmp, &res, &buflen); | ||
2105 | if (!error && !path_equal(&tmp, &root)) | ||
2106 | error = prepend_unreachable(&res, &buflen); | ||
2107 | spin_unlock(&dcache_lock); | ||
2108 | path_put(&root); | ||
2109 | if (error) | ||
2110 | res = ERR_PTR(error); | ||
2111 | |||
2112 | return res; | ||
2113 | } | ||
2114 | |||
2028 | /* | 2115 | /* |
2029 | * Helper function for dentry_operations.d_dname() members | 2116 | * Helper function for dentry_operations.d_dname() members |
2030 | */ | 2117 | */ |
@@ -2049,16 +2136,12 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen, | |||
2049 | /* | 2136 | /* |
2050 | * Write full pathname from the root of the filesystem into the buffer. | 2137 | * Write full pathname from the root of the filesystem into the buffer. |
2051 | */ | 2138 | */ |
2052 | char *dentry_path(struct dentry *dentry, char *buf, int buflen) | 2139 | char *__dentry_path(struct dentry *dentry, char *buf, int buflen) |
2053 | { | 2140 | { |
2054 | char *end = buf + buflen; | 2141 | char *end = buf + buflen; |
2055 | char *retval; | 2142 | char *retval; |
2056 | 2143 | ||
2057 | spin_lock(&dcache_lock); | ||
2058 | prepend(&end, &buflen, "\0", 1); | 2144 | prepend(&end, &buflen, "\0", 1); |
2059 | if (d_unlinked(dentry) && | ||
2060 | (prepend(&end, &buflen, "//deleted", 9) != 0)) | ||
2061 | goto Elong; | ||
2062 | if (buflen < 1) | 2145 | if (buflen < 1) |
2063 | goto Elong; | 2146 | goto Elong; |
2064 | /* Get '/' right */ | 2147 | /* Get '/' right */ |
@@ -2076,7 +2159,28 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen) | |||
2076 | retval = end; | 2159 | retval = end; |
2077 | dentry = parent; | 2160 | dentry = parent; |
2078 | } | 2161 | } |
2162 | return retval; | ||
2163 | Elong: | ||
2164 | return ERR_PTR(-ENAMETOOLONG); | ||
2165 | } | ||
2166 | EXPORT_SYMBOL(__dentry_path); | ||
2167 | |||
2168 | char *dentry_path(struct dentry *dentry, char *buf, int buflen) | ||
2169 | { | ||
2170 | char *p = NULL; | ||
2171 | char *retval; | ||
2172 | |||
2173 | spin_lock(&dcache_lock); | ||
2174 | if (d_unlinked(dentry)) { | ||
2175 | p = buf + buflen; | ||
2176 | if (prepend(&p, &buflen, "//deleted", 10) != 0) | ||
2177 | goto Elong; | ||
2178 | buflen++; | ||
2179 | } | ||
2180 | retval = __dentry_path(dentry, buf, buflen); | ||
2079 | spin_unlock(&dcache_lock); | 2181 | spin_unlock(&dcache_lock); |
2182 | if (!IS_ERR(retval) && p) | ||
2183 | *p = '/'; /* restore '/' overriden with '\0' */ | ||
2080 | return retval; | 2184 | return retval; |
2081 | Elong: | 2185 | Elong: |
2082 | spin_unlock(&dcache_lock); | 2186 | spin_unlock(&dcache_lock); |
@@ -2110,27 +2214,30 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) | |||
2110 | if (!page) | 2214 | if (!page) |
2111 | return -ENOMEM; | 2215 | return -ENOMEM; |
2112 | 2216 | ||
2113 | read_lock(¤t->fs->lock); | 2217 | get_fs_root_and_pwd(current->fs, &root, &pwd); |
2114 | pwd = current->fs->pwd; | ||
2115 | path_get(&pwd); | ||
2116 | root = current->fs->root; | ||
2117 | path_get(&root); | ||
2118 | read_unlock(¤t->fs->lock); | ||
2119 | 2218 | ||
2120 | error = -ENOENT; | 2219 | error = -ENOENT; |
2121 | spin_lock(&dcache_lock); | 2220 | spin_lock(&dcache_lock); |
2122 | if (!d_unlinked(pwd.dentry)) { | 2221 | if (!d_unlinked(pwd.dentry)) { |
2123 | unsigned long len; | 2222 | unsigned long len; |
2124 | struct path tmp = root; | 2223 | struct path tmp = root; |
2125 | char * cwd; | 2224 | char *cwd = page + PAGE_SIZE; |
2225 | int buflen = PAGE_SIZE; | ||
2126 | 2226 | ||
2127 | cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE); | 2227 | prepend(&cwd, &buflen, "\0", 1); |
2228 | error = prepend_path(&pwd, &tmp, &cwd, &buflen); | ||
2128 | spin_unlock(&dcache_lock); | 2229 | spin_unlock(&dcache_lock); |
2129 | 2230 | ||
2130 | error = PTR_ERR(cwd); | 2231 | if (error) |
2131 | if (IS_ERR(cwd)) | ||
2132 | goto out; | 2232 | goto out; |
2133 | 2233 | ||
2234 | /* Unreachable from current root */ | ||
2235 | if (!path_equal(&tmp, &root)) { | ||
2236 | error = prepend_unreachable(&cwd, &buflen); | ||
2237 | if (error) | ||
2238 | goto out; | ||
2239 | } | ||
2240 | |||
2134 | error = -ERANGE; | 2241 | error = -ERANGE; |
2135 | len = PAGE_SIZE + page - cwd; | 2242 | len = PAGE_SIZE + page - cwd; |
2136 | if (len <= size) { | 2243 | if (len <= size) { |
@@ -2195,11 +2302,12 @@ int path_is_under(struct path *path1, struct path *path2) | |||
2195 | struct vfsmount *mnt = path1->mnt; | 2302 | struct vfsmount *mnt = path1->mnt; |
2196 | struct dentry *dentry = path1->dentry; | 2303 | struct dentry *dentry = path1->dentry; |
2197 | int res; | 2304 | int res; |
2198 | spin_lock(&vfsmount_lock); | 2305 | |
2306 | br_read_lock(vfsmount_lock); | ||
2199 | if (mnt != path2->mnt) { | 2307 | if (mnt != path2->mnt) { |
2200 | for (;;) { | 2308 | for (;;) { |
2201 | if (mnt->mnt_parent == mnt) { | 2309 | if (mnt->mnt_parent == mnt) { |
2202 | spin_unlock(&vfsmount_lock); | 2310 | br_read_unlock(vfsmount_lock); |
2203 | return 0; | 2311 | return 0; |
2204 | } | 2312 | } |
2205 | if (mnt->mnt_parent == path2->mnt) | 2313 | if (mnt->mnt_parent == path2->mnt) |
@@ -2209,7 +2317,7 @@ int path_is_under(struct path *path1, struct path *path2) | |||
2209 | dentry = mnt->mnt_mountpoint; | 2317 | dentry = mnt->mnt_mountpoint; |
2210 | } | 2318 | } |
2211 | res = is_subdir(dentry, path2->dentry); | 2319 | res = is_subdir(dentry, path2->dentry); |
2212 | spin_unlock(&vfsmount_lock); | 2320 | br_read_unlock(vfsmount_lock); |
2213 | return res; | 2321 | return res; |
2214 | } | 2322 | } |
2215 | EXPORT_SYMBOL(path_is_under); | 2323 | EXPORT_SYMBOL(path_is_under); |